- Timestamp:
- Jan 7, 2021, 2:55:57 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 58fe85a
- Parents:
- bdfc032 (diff), 44e37ef (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- src
- Files:
-
- 12 added
- 1 deleted
- 162 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Attribute.hpp
rbdfc032 reef8dfb 51 51 template<typename node_t> 52 52 friend node_t * mutate(const node_t * node); 53 template<typename node_t> 54 friend node_t * shallowCopy(const node_t * node); 53 55 }; 54 56 -
src/AST/CVQualifiers.hpp
rbdfc032 reef8dfb 27 27 Restrict = 1 << 1, 28 28 Volatile = 1 << 2, 29 Lvalue = 1 << 3, 30 Mutex = 1 << 4, 31 Atomic = 1 << 5, 32 NumQualifiers = 6 29 Mutex = 1 << 3, 30 Atomic = 1 << 4, 31 NumQualifiers = 5 33 32 }; 34 33 35 34 /// Mask for equivalence-preserving qualfiers 36 enum { EquivQualifiers = ~ (Restrict | Lvalue)};35 enum { EquivQualifiers = ~Restrict }; 37 36 38 37 /// Underlying data for qualifiers … … 44 43 bool is_restrict : 1; 45 44 bool is_volatile : 1; 46 bool is_lvalue : 1;47 45 bool is_mutex : 1; 48 46 bool is_atomic : 1; -
src/AST/Convert.cpp
rbdfc032 reef8dfb 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu May 09 15::37::05 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Dec 11 21:39:32 201913 // Update Count : 3 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Nov 12 10:07:00 2020 13 // Update Count : 34 14 14 // 15 15 … … 20 20 21 21 #include "AST/Attribute.hpp" 22 #include "AST/Copy.hpp" 22 23 #include "AST/Decl.hpp" 23 24 #include "AST/Expr.hpp" 24 25 #include "AST/Init.hpp" 25 26 #include "AST/Stmt.hpp" 27 #include "AST/TranslationUnit.hpp" 26 28 #include "AST/TypeSubstitution.hpp" 27 29 … … 46 48 47 49 //================================================================================================ 48 namespace {50 namespace ast { 49 51 50 52 // This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not) 51 53 // allow us to use the same stratagy in the new ast. 52 ast::Type * sizeType = nullptr; 53 ast::FunctionDecl * dereferenceOperator = nullptr; 54 ast::StructDecl * dtorStruct = nullptr; 55 ast::FunctionDecl * dtorStructDestroy = nullptr; 54 // xxx - since convert back pass works, this concern seems to be unnecessary. 55 56 // these need to be accessed in new FixInit now 57 ast::ptr<ast::Type> sizeType = nullptr; 58 const ast::FunctionDecl * dereferenceOperator = nullptr; 59 const ast::StructDecl * dtorStruct = nullptr; 60 const ast::FunctionDecl * dtorStructDestroy = nullptr; 56 61 57 62 } … … 62 67 using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >; 63 68 Cache cache; 69 70 // Statements can no longer be shared. 71 // however, since StmtExprResult is now implemented, need to still maintain 72 // readonly references. 73 Cache readonlyCache; 64 74 65 75 template<typename T> … … 153 163 } 154 164 155 const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final { 156 auto&& bfwd = get<Expression>().accept1( node->bitfieldWidth ); 157 auto&& type = get<Type>().accept1( node->type ); 158 auto&& init = get<Initializer>().accept1( node->init ); 159 auto&& attr = get<Attribute>().acceptL( node->attributes ); 165 const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final { 160 166 if ( inCache( node ) ) { 161 167 return nullptr; 162 168 } 169 auto bfwd = get<Expression>().accept1( node->bitfieldWidth ); 170 auto type = get<Type>().accept1( node->type ); 171 auto attr = get<Attribute>().acceptL( node->attributes ); 172 163 173 auto decl = new ObjectDecl( 164 174 node->name, … … 166 176 LinkageSpec::Spec( node->linkage.val ), 167 177 bfwd, 168 type ,169 init,178 type->clone(), 179 nullptr, // prevent infinite loop 170 180 attr, 171 181 Type::FuncSpecifiers( node->funcSpec.val ) 172 182 ); 173 return declWithTypePostamble( decl, node ); 183 184 // handles the case where node->init references itself 185 // xxx - does it really happen? 186 declWithTypePostamble(decl, node); 187 auto init = get<Initializer>().accept1( node->init ); 188 decl->init = init; 189 190 this->node = decl; 191 return nullptr; 174 192 } 175 193 176 194 const ast::DeclWithType * visit( const ast::FunctionDecl * node ) override final { 177 195 if ( inCache( node ) ) return nullptr; 196 197 // function decl contains real variables that the type must use. 198 // the structural change means function type in and out of decl 199 // must be handled **differently** on convert back to old. 200 auto ftype = new FunctionType( 201 cv(node->type), 202 (bool)node->type->isVarArgs 203 ); 204 ftype->returnVals = get<DeclarationWithType>().acceptL(node->returns); 205 ftype->parameters = get<DeclarationWithType>().acceptL(node->params); 206 207 ftype->forall = get<TypeDecl>().acceptL( node->type_params ); 208 if (!node->assertions.empty()) { 209 assert(!ftype->forall.empty()); 210 // find somewhere to place assertions back, for convenience it is the last slot 211 ftype->forall.back()->assertions = get<DeclarationWithType>().acceptL(node->assertions); 212 } 213 214 visitType(node->type, ftype); 215 178 216 auto decl = new FunctionDecl( 179 217 node->name, 180 218 Type::StorageClasses( node->storage.val ), 181 219 LinkageSpec::Spec( node->linkage.val ), 182 get<FunctionType>().accept1( node->type ), 220 ftype, 221 //get<FunctionType>().accept1( node->type ), 183 222 {}, 184 223 get<Attribute>().acceptL( node->attributes ), … … 188 227 decl->statements = get<CompoundStmt>().accept1( node->stmts ); 189 228 decl->withExprs = get<Expression>().acceptL( node->withExprs ); 190 if ( dereferenceOperator == node ) {229 if ( ast::dereferenceOperator == node ) { 191 230 Validate::dereferenceOperator = decl; 192 231 } 193 if ( dtorStructDestroy == node ) {232 if ( ast::dtorStructDestroy == node ) { 194 233 Validate::dtorStructDestroy = decl; 195 234 } … … 199 238 const ast::Decl * namedTypePostamble( NamedTypeDecl * decl, const ast::NamedTypeDecl * node ) { 200 239 // base comes from constructor 201 decl->parameters = get<TypeDecl>().acceptL( node->params );202 240 decl->assertions = get<DeclarationWithType>().acceptL( node->assertions ); 203 241 declPostamble( decl, node ); … … 250 288 ); 251 289 252 if ( dtorStruct == node ) {290 if ( ast::dtorStruct == node ) { 253 291 Validate::dtorStruct = decl; 254 292 } … … 303 341 304 342 const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) { 305 cache.emplace( node, stmt ); 343 // force statements in old tree to be unique. 344 // cache.emplace( node, stmt ); 345 readonlyCache.emplace( node, stmt ); 306 346 stmt->location = node->location; 307 347 stmt->labels = makeLabelL( stmt, node->labels ); … … 320 360 if ( inCache( node ) ) return nullptr; 321 361 auto stmt = new ExprStmt( nullptr ); 322 cache.emplace( node, stmt );323 362 stmt->expr = get<Expression>().accept1( node->expr ); 324 363 return stmtPostamble( stmt, node ); … … 493 532 } 494 533 534 const ast::Stmt * visit(const ast::SuspendStmt * node ) override final { 535 if ( inCache( node ) ) return nullptr; 536 auto stmt = new SuspendStmt(); 537 stmt->then = get<CompoundStmt>().accept1( node->then ); 538 switch(node->type) { 539 case ast::SuspendStmt::None : stmt->type = SuspendStmt::None ; break; 540 case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break; 541 case ast::SuspendStmt::Generator: stmt->type = SuspendStmt::Generator; break; 542 } 543 return stmtPostamble( stmt, node ); 544 } 545 495 546 const ast::Stmt * visit( const ast::WaitForStmt * node ) override final { 496 547 if ( inCache( node ) ) return nullptr; … … 556 607 557 608 for (decltype(src->begin()) src_i = src->begin(); src_i != src->end(); src_i++) { 558 rslt->add( src_i->first ,609 rslt->add( src_i->first.typeString(), 559 610 get<Type>().accept1(src_i->second) ); 560 }561 562 for (decltype(src->beginVar()) src_i = src->beginVar(); src_i != src->endVar(); src_i++) {563 rslt->addVar( src_i->first,564 get<Expression>().accept1(src_i->second) );565 611 } 566 612 … … 575 621 assert( tgtResnSlots.empty() ); 576 622 577 if ( srcInferred. mode == ast::Expr::InferUnion::Params ) {623 if ( srcInferred.data.inferParams ) { 578 624 const ast::InferredParams &srcParams = srcInferred.inferParams(); 579 625 for (auto & srcParam : srcParams) { … … 581 627 srcParam.second.decl, 582 628 get<Declaration>().accept1(srcParam.second.declptr), 583 get<Type>().accept1(srcParam.second.actualType) ,584 get<Type>().accept1(srcParam.second.formalType) ,585 get<Expression>().accept1(srcParam.second.expr) 629 get<Type>().accept1(srcParam.second.actualType)->clone(), 630 get<Type>().accept1(srcParam.second.formalType)->clone(), 631 get<Expression>().accept1(srcParam.second.expr)->clone() 586 632 )); 587 633 assert(res.second); 588 634 } 589 } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots ) { 635 } 636 if ( srcInferred.data.resnSlots ) { 590 637 const ast::ResnSlots &srcSlots = srcInferred.resnSlots(); 591 638 for (auto srcSlot : srcSlots) { … … 608 655 609 656 tgt->result = get<Type>().accept1(src->result); 657 // Unconditionally use a clone of the result type. 658 // We know this will leak some objects: much of the immediate conversion result. 659 // In some cases, using the conversion result directly gives unintended object sharing. 660 // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache. 661 // But tgt->result must be fully owned privately by tgt. 662 // Applying these conservative copies here means 663 // - weak references point at the declaration's copy, not these expr.result copies (good) 664 // - we copy more objects than really needed (bad, tolerated) 665 if (tgt->result) { 666 tgt->result = tgt->result->clone(); 667 } 610 668 return visitBaseExpr_skipResultType(src, tgt); 611 669 } … … 680 738 new KeywordCastExpr( 681 739 get<Expression>().accept1(node->arg), 682 castTarget 740 castTarget, 741 {node->concrete_target.field, node->concrete_target.getter} 683 742 ) 684 743 ); … … 967 1026 968 1027 const ast::Expr * visit( const ast::StmtExpr * node ) override final { 1028 auto stmts = node->stmts; 1029 // disable sharing between multiple StmtExprs explicitly. 1030 // this should no longer be true. 1031 969 1032 auto rslt = new StmtExpr( 970 get<CompoundStmt>().accept1( node->stmts)1033 get<CompoundStmt>().accept1(stmts) 971 1034 ); 972 1035 973 1036 rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls); 974 1037 rslt->dtors = get<Expression>().acceptL(node->dtors); 1038 if (node->resultExpr) { 1039 // this MUST be found by children visit 1040 rslt->resultExpr = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr)); 1041 } 975 1042 976 1043 auto expr = visitBaseExpr( node, rslt ); … … 989 1056 990 1057 auto expr = visitBaseExpr( node, rslt ); 991 this->node = expr ;1058 this->node = expr->clone(); 992 1059 return nullptr; 993 1060 } … … 1079 1146 auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind }; 1080 1147 // I believe this should always be a BasicType. 1081 if ( sizeType == node ) {1148 if ( ast::sizeType == node ) { 1082 1149 Validate::SizeType = type; 1083 1150 } … … 1121 1188 1122 1189 const ast::Type * visit( const ast::FunctionType * node ) override final { 1190 static std::string dummy_paramvar_prefix = "__param_"; 1191 static std::string dummy_returnvar_prefix = "__retval_"; 1192 1123 1193 auto ty = new FunctionType { 1124 1194 cv( node ), 1125 1195 (bool)node->isVarArgs 1126 1196 }; 1127 ty->returnVals = get<DeclarationWithType>().acceptL( node->returns ); 1128 ty->parameters = get<DeclarationWithType>().acceptL( node->params ); 1129 ty->forall = get<TypeDecl>().acceptL( node->forall ); 1197 auto returns = get<Type>().acceptL(node->returns); 1198 auto params = get<Type>().acceptL(node->params); 1199 1200 int ret_index = 0; 1201 for (auto t: returns) { 1202 // xxx - LinkageSpec shouldn't matter but needs to be something 1203 ObjectDecl * dummy = new ObjectDecl(dummy_returnvar_prefix + std::to_string(ret_index++), {}, LinkageSpec::C, nullptr, t, nullptr); 1204 ty->returnVals.push_back(dummy); 1205 } 1206 int param_index = 0; 1207 for (auto t: params) { 1208 ObjectDecl * dummy = new ObjectDecl(dummy_paramvar_prefix + std::to_string(param_index++), {}, LinkageSpec::C, nullptr, t, nullptr); 1209 ty->parameters.push_back(dummy); 1210 } 1211 1212 // ty->returnVals = get<DeclarationWithType>().acceptL( node->returns ); 1213 // ty->parameters = get<DeclarationWithType>().acceptL( node->params ); 1214 1215 auto types = get<TypeInstType>().acceptL( node->forall ); 1216 for (auto t : types) { 1217 auto newT = new TypeDecl(*t->baseType); 1218 newT->name = t->name; // converted by typeString() 1219 for (auto asst : newT->assertions) delete asst; 1220 newT->assertions.clear(); 1221 ty->forall.push_back(newT); 1222 } 1223 auto assts = get<VariableExpr>().acceptL( node->assertions ); 1224 if (!assts.empty()) { 1225 assert(!types.empty()); 1226 for (auto asst : assts) { 1227 auto newDecl = new ObjectDecl(*strict_dynamic_cast<ObjectDecl*>(asst->var)); 1228 delete newDecl->type; 1229 newDecl->type = asst->result->clone(); 1230 newDecl->storageClasses.is_extern = true; // hack 1231 ty->forall.back()->assertions.push_back(newDecl); 1232 } 1233 } 1234 1130 1235 return visitType( node, ty ); 1131 1236 } 1132 1237 1133 const ast::Type * postvisit( const ast::ReferenceToType * old, ReferenceToType * ty ) { 1134 ty->forall = get<TypeDecl>().acceptL( old->forall ); 1238 const ast::Type * postvisit( const ast::BaseInstType * old, ReferenceToType * ty ) { 1135 1239 ty->parameters = get<Expression>().acceptL( old->params ); 1136 1240 ty->hoistType = old->hoistType; … … 1215 1319 ty = new TypeInstType{ 1216 1320 cv( node ), 1217 node-> name,1321 node->typeString(), 1218 1322 get<TypeDecl>().accept1( node->base ), 1219 1323 get<Attribute>().acceptL( node->attributes ) … … 1222 1326 ty = new TypeInstType{ 1223 1327 cv( node ), 1224 node-> name,1328 node->typeString(), 1225 1329 node->kind == ast::TypeDecl::Ftype, 1226 1330 get<Attribute>().acceptL( node->attributes ) … … 1319 1423 }; 1320 1424 1321 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > >&& translationUnit ) {1425 std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ) { 1322 1426 ConverterNewToOld c; 1323 1427 std::list< Declaration * > decls; 1324 for(auto d : translationUnit ) {1428 for(auto d : translationUnit.decls) { 1325 1429 decls.emplace_back( c.decl( d ) ); 1326 1430 } … … 1343 1447 ast::Node * node = nullptr; 1344 1448 /// cache of nodes that might be referenced by readonly<> for de-duplication 1345 std::unordered_map< const BaseSyntaxNode *, ast::Node * > cache = {}; 1449 /// in case that some nodes are dropped by conversion (due to possible structural change) 1450 /// use smart pointers in cache value to prevent accidental invalidation. 1451 /// at conversion stage, all created nodes are guaranteed to be unique, therefore 1452 /// const_casting out of smart pointers is permitted. 1453 std::unordered_map< const BaseSyntaxNode *, ast::readonly<ast::Node> > cache = {}; 1346 1454 1347 1455 // Local Utilities: … … 1416 1524 auto it = cache.find( old ); 1417 1525 if ( it == cache.end() ) return false; 1418 node = it->second;1526 node = const_cast<ast::Node *>(it->second.get()); 1419 1527 return true; 1420 1528 } … … 1455 1563 virtual void visit( const FunctionDecl * old ) override final { 1456 1564 if ( inCache( old ) ) return; 1565 auto paramVars = GET_ACCEPT_V(type->parameters, DeclWithType); 1566 auto returnVars = GET_ACCEPT_V(type->returnVals, DeclWithType); 1567 auto forall = GET_ACCEPT_V(type->forall, TypeDecl); 1568 1569 // function type is now derived from parameter decls instead of storing them 1570 1571 /* 1572 auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type)); 1573 ftype->params.reserve(paramVars.size()); 1574 ftype->returns.reserve(returnVars.size()); 1575 1576 for (auto & v: paramVars) { 1577 ftype->params.emplace_back(v->get_type()); 1578 } 1579 for (auto & v: returnVars) { 1580 ftype->returns.emplace_back(v->get_type()); 1581 } 1582 ftype->forall = std::move(forall); 1583 */ 1584 1585 // can function type have attributes? seems not to be the case. 1586 // visitType(old->type, ftype); 1587 1588 // collect assertions and put directly in FunctionDecl 1589 std::vector<ast::ptr<ast::DeclWithType>> assertions; 1590 for (auto & param: forall) { 1591 for (auto & asst: param->assertions) { 1592 assertf(asst->unique(), "newly converted decl must be unique"); 1593 assertions.emplace_back(asst); 1594 } 1595 auto mut = param.get_and_mutate(); 1596 assertf(mut == param, "newly converted decl must be unique"); 1597 mut->assertions.clear(); 1598 } 1599 1457 1600 auto decl = new ast::FunctionDecl{ 1458 1601 old->location, 1459 1602 old->name, 1460 GET_ACCEPT_1(type, FunctionType), 1603 // GET_ACCEPT_1(type, FunctionType), 1604 std::move(forall), 1605 std::move(paramVars), 1606 std::move(returnVars), 1461 1607 {}, 1462 1608 { old->storageClasses.val }, 1463 1609 { old->linkage.val }, 1464 1610 GET_ACCEPT_V(attributes, Attribute), 1465 { old->get_funcSpec().val } 1611 { old->get_funcSpec().val }, 1612 old->type->isVarArgs 1466 1613 }; 1614 1615 // decl->type = ftype; 1467 1616 cache.emplace( old, decl ); 1617 1618 decl->assertions = std::move(assertions); 1468 1619 decl->withExprs = GET_ACCEPT_V(withExprs, Expr); 1469 1620 decl->stmts = GET_ACCEPT_1(statements, CompoundStmt); … … 1478 1629 1479 1630 if ( Validate::dereferenceOperator == old ) { 1480 dereferenceOperator = decl;1631 ast::dereferenceOperator = decl; 1481 1632 } 1482 1633 1483 1634 if ( Validate::dtorStructDestroy == old ) { 1484 dtorStructDestroy = decl;1635 ast::dtorStructDestroy = decl; 1485 1636 } 1486 1637 } … … 1507 1658 1508 1659 if ( Validate::dtorStruct == old ) { 1509 dtorStruct = decl;1660 ast::dtorStruct = decl; 1510 1661 } 1511 1662 } … … 1584 1735 cache.emplace( old, decl ); 1585 1736 decl->assertions = GET_ACCEPT_V(assertions, DeclWithType); 1586 decl->params = GET_ACCEPT_V(parameters, TypeDecl);1587 1737 decl->extension = old->extension; 1588 1738 decl->uniqueId = old->uniqueId; … … 1600 1750 ); 1601 1751 decl->assertions = GET_ACCEPT_V(assertions, DeclWithType); 1602 decl->params = GET_ACCEPT_V(parameters, TypeDecl);1603 1752 decl->extension = old->extension; 1604 1753 decl->uniqueId = old->uniqueId; … … 1859 2008 } 1860 2009 2010 virtual void visit( const SuspendStmt * old ) override final { 2011 if ( inCache( old ) ) return; 2012 ast::SuspendStmt::Type type; 2013 switch (old->type) { 2014 case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break; 2015 case SuspendStmt::Generator: type = ast::SuspendStmt::Generator; break; 2016 case SuspendStmt::None : type = ast::SuspendStmt::None ; break; 2017 default: abort(); 2018 } 2019 this->node = new ast::SuspendStmt( 2020 old->location, 2021 GET_ACCEPT_1(then , CompoundStmt), 2022 type, 2023 GET_LABELS_V(old->labels) 2024 ); 2025 cache.emplace( old, this->node ); 2026 } 2027 1861 2028 virtual void visit( const WaitForStmt * old ) override final { 1862 2029 if ( inCache( old ) ) return; … … 1932 2099 } 1933 2100 2101 // TypeSubstitution shouldn't exist yet in old. 1934 2102 ast::TypeSubstitution * convertTypeSubstitution(const TypeSubstitution * old) { 1935 2103 1936 2104 if (!old) return nullptr; 1937 2105 if (old->empty()) return nullptr; 2106 assert(false); 2107 2108 /* 1938 2109 ast::TypeSubstitution *rslt = new ast::TypeSubstitution(); 1939 2110 … … 1943 2114 } 1944 2115 1945 for (decltype(old->beginVar()) old_i = old->beginVar(); old_i != old->endVar(); old_i++) {1946 rslt->addVar( old_i->first,1947 getAccept1<ast::Expr>(old_i->second) );1948 }1949 1950 2116 return rslt; 2117 */ 1951 2118 } 1952 2119 … … 1956 2123 1957 2124 assert( oldInferParams.empty() || oldResnSlots.empty() ); 1958 assert( newInferred.mode == ast::Expr::InferUnion::Empty );2125 // assert( newInferred.mode == ast::Expr::InferUnion::Empty ); 1959 2126 1960 2127 if ( !oldInferParams.empty() ) { … … 2039 2206 old->location, 2040 2207 GET_ACCEPT_1(arg, Expr), 2041 castTarget 2208 castTarget, 2209 {old->concrete_target.field, old->concrete_target.getter} 2042 2210 ) 2043 2211 ); … … 2087 2255 old->location, 2088 2256 GET_ACCEPT_1(member, DeclWithType), 2089 GET_ACCEPT_1(aggregate, Expr) 2257 GET_ACCEPT_1(aggregate, Expr), 2258 ast::MemberExpr::NoOpConstructionChosen 2090 2259 ) 2091 2260 ); … … 2419 2588 // I believe this should always be a BasicType. 2420 2589 if ( Validate::SizeType == old ) { 2421 sizeType = type;2590 ast::sizeType = type; 2422 2591 } 2423 2592 visitType( old, type ); … … 2464 2633 cv( old ) 2465 2634 }; 2466 ty->returns = GET_ACCEPT_V( returnVals, DeclWithType ); 2467 ty->params = GET_ACCEPT_V( parameters, DeclWithType ); 2468 ty->forall = GET_ACCEPT_V( forall, TypeDecl ); 2635 auto returnVars = GET_ACCEPT_V(returnVals, DeclWithType); 2636 auto paramVars = GET_ACCEPT_V(parameters, DeclWithType); 2637 // ty->returns = GET_ACCEPT_V( returnVals, DeclWithType ); 2638 // ty->params = GET_ACCEPT_V( parameters, DeclWithType ); 2639 for (auto & v: returnVars) { 2640 ty->returns.emplace_back(v->get_type()); 2641 } 2642 for (auto & v: paramVars) { 2643 ty->params.emplace_back(v->get_type()); 2644 } 2645 // xxx - when will this be non-null? 2646 // will have to create dangling (no-owner) decls to be pointed to 2647 auto foralls = GET_ACCEPT_V( forall, TypeDecl ); 2648 2649 for (auto & param : foralls) { 2650 ty->forall.emplace_back(new ast::TypeInstType(param->name, param)); 2651 for (auto asst : param->assertions) { 2652 ty->assertions.emplace_back(new ast::VariableExpr({}, asst)); 2653 } 2654 } 2469 2655 visitType( old, ty ); 2470 2656 } 2471 2657 2472 void postvisit( const ReferenceToType * old, ast::ReferenceToType * ty ) { 2473 ty->forall = GET_ACCEPT_V( forall, TypeDecl ); 2658 void postvisit( const ReferenceToType * old, ast::BaseInstType * ty ) { 2474 2659 ty->params = GET_ACCEPT_V( parameters, Expr ); 2475 2660 ty->hoistType = old->hoistType; … … 2616 2801 old->location, 2617 2802 GET_ACCEPT_1(value, Expr), 2618 (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast:: DoConstruct2803 (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::NoConstruct 2619 2804 ); 2620 2805 } … … 2625 2810 GET_ACCEPT_V(initializers, Init), 2626 2811 GET_ACCEPT_V(designations, Designation), 2627 (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast:: DoConstruct2812 (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::NoConstruct 2628 2813 ); 2629 2814 } … … 2656 2841 #undef GET_ACCEPT_1 2657 2842 2658 std::list< ast::ptr< ast::Decl > >convert( const std::list< Declaration * > && translationUnit ) {2843 ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit ) { 2659 2844 ConverterOldToNew c; 2660 std::list< ast::ptr< ast::Decl > > decls; 2845 ast::TranslationUnit unit; 2846 if (Validate::SizeType) { 2847 // this should be a BasicType. 2848 auto old = strict_dynamic_cast<BasicType *>(Validate::SizeType); 2849 ast::sizeType = new ast::BasicType{ (ast::BasicType::Kind)(unsigned)old->kind }; 2850 } 2851 2661 2852 for(auto d : translationUnit) { 2662 2853 d->accept( c ); 2663 decls.emplace_back( c.decl() );2854 unit.decls.emplace_back( c.decl() ); 2664 2855 } 2665 2856 deleteAll(translationUnit); 2666 return decls; 2857 2858 // Load the local static varables into the global store. 2859 unit.global.sizeType = ast::sizeType; 2860 unit.global.dereference = ast::dereferenceOperator; 2861 unit.global.dtorStruct = ast::dtorStruct; 2862 unit.global.dtorDestroy = ast::dtorStructDestroy; 2863 2864 return unit; 2667 2865 } -
src/AST/Convert.hpp
rbdfc032 reef8dfb 18 18 #include <list> 19 19 20 #include "AST/Node.hpp"21 22 20 class Declaration; 23 21 namespace ast { 24 class Decl;22 struct TranslationUnit; 25 23 }; 26 24 27 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > >&& translationUnit );28 std::list< ast::ptr< ast::Decl > >convert( const std::list< Declaration * > && translationUnit );25 std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ); 26 ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit ); -
src/AST/Decl.cpp
rbdfc032 reef8dfb 49 49 // --- FunctionDecl 50 50 51 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 52 std::vector<ptr<TypeDecl>>&& forall, 53 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 54 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage, 55 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs) 56 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)), 57 type_params(std::move(forall)), stmts( stmts ) { 58 FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs)); 59 for (auto & param : this->params) { 60 ftype->params.emplace_back(param->get_type()); 61 } 62 for (auto & ret : this->returns) { 63 ftype->returns.emplace_back(ret->get_type()); 64 } 65 for (auto & tp : this->type_params) { 66 ftype->forall.emplace_back(new TypeInstType(tp->name, tp)); 67 } 68 this->type = ftype; 69 } 70 71 51 72 const Type * FunctionDecl::get_type() const { return type.get(); } 52 void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); } 73 void FunctionDecl::set_type( const Type * t ) { 74 type = strict_dynamic_cast< const FunctionType * >( t ); 75 } 53 76 54 77 // --- TypeDecl -
src/AST/Decl.hpp
rbdfc032 reef8dfb 33 33 34 34 // Must be included in *all* AST classes; should be #undef'd at the end of the file 35 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 35 #define MUTATE_FRIEND \ 36 template<typename node_t> friend node_t * mutate(const node_t * node); \ 37 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 36 38 37 39 namespace ast { … … 77 79 ptr<Expr> asmName; 78 80 bool isDeleted = false; 81 bool isTypeFixed = false; 79 82 80 83 DeclWithType( const CodeLocation& loc, const std::string& name, Storage::Classes storage, … … 88 91 virtual const Type * get_type() const = 0; 89 92 /// Set type of this declaration. May be verified by subclass 90 virtual void set_type( Type *) = 0;93 virtual void set_type( const Type * ) = 0; 91 94 92 95 const DeclWithType * accept( Visitor & v ) const override = 0; … … 111 114 112 115 const Type* get_type() const override { return type; } 113 void set_type( Type * ty ) override { type = ty; }116 void set_type( const Type * ty ) override { type = ty; } 114 117 115 118 const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); } … … 122 125 class FunctionDecl : public DeclWithType { 123 126 public: 127 std::vector<ptr<DeclWithType>> params; 128 std::vector<ptr<DeclWithType>> returns; 129 std::vector<ptr<TypeDecl>> type_params; 130 std::vector<ptr<DeclWithType>> assertions; 131 // declared type, derived from parameter declarations 124 132 ptr<FunctionType> type; 125 133 ptr<CompoundStmt> stmts; 126 134 std::vector< ptr<Expr> > withExprs; 127 135 128 FunctionDecl( const CodeLocation & loc, const std::string & name, FunctionType * type, 136 137 FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall, 138 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 129 139 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, 130 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {} )131 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type),132 stmts( stmts ) {}140 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false); 141 // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)), 142 // stmts( stmts ) {} 133 143 134 144 const Type * get_type() const override; 135 void set_type( Type * t) override;145 void set_type( const Type * t ) override; 136 146 137 147 bool has_body() const { return stmts; } … … 147 157 public: 148 158 ptr<Type> base; 149 std::vector<ptr<TypeDecl>> params;150 159 std::vector<ptr<DeclWithType>> assertions; 151 160 152 NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 153 Type* b, Linkage::Spec spec = Linkage::Cforall ) 154 : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {} 161 NamedTypeDecl( 162 const CodeLocation & loc, const std::string & name, Storage::Classes storage, 163 const Type * b, Linkage::Spec spec = Linkage::Cforall ) 164 : Decl( loc, name, storage, spec ), base( b ), assertions() {} 155 165 156 166 /// Produces a name for the kind of alias … … 186 196 }; 187 197 188 TypeDecl( const CodeLocation & loc, const std::string & name, Storage::Classes storage, Type * b, 189 Kind k, bool s, Type * i = nullptr ) 190 : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ), 191 init( i ) {} 198 TypeDecl( 199 const CodeLocation & loc, const std::string & name, Storage::Classes storage, 200 const Type * b, TypeDecl::Kind k, bool s, const Type * i = nullptr ) 201 : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeDecl::Ttype || s ), 202 init( i ) {} 192 203 193 204 const char * typeString() const override; … … 259 270 260 271 bool is_coroutine() { return kind == Coroutine; } 261 bool is_monitor() { return kind == Monitor; } 262 bool is_thread() { return kind == Thread; } 272 bool is_generator() { return kind == Generator; } 273 bool is_monitor () { return kind == Monitor ; } 274 bool is_thread () { return kind == Thread ; } 263 275 264 276 const Decl * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/DeclReplacer.cpp
rbdfc032 reef8dfb 38 38 const ast::TypeInstType * previsit( const ast::TypeInstType * ); 39 39 }; 40 41 struct VarExprReplacer { 42 private: 43 const ExprMap & exprMap; 44 45 public: 46 VarExprReplacer(const ExprMap & exprMap): exprMap (exprMap) {} 47 48 const Expr * postvisit (const VariableExpr *); 49 }; 40 50 } 41 51 … … 54 64 DeclMap declMap; 55 65 return replace( node, declMap, typeMap, debug ); 66 } 67 68 const ast::Node * replace( const ast::Node * node, const ExprMap & exprMap) { 69 Pass<VarExprReplacer> replacer = {exprMap}; 70 return node->accept( replacer ); 56 71 } 57 72 … … 88 103 return ninst; 89 104 } 105 106 const Expr * VarExprReplacer::postvisit( const VariableExpr * expr ) { 107 if (!exprMap.count(expr->var)) return expr; 108 109 return exprMap.at(expr->var); 110 } 111 90 112 } 91 113 } -
src/AST/DeclReplacer.hpp
rbdfc032 reef8dfb 23 23 class DeclWithType; 24 24 class TypeDecl; 25 class Expr; 25 26 26 27 namespace DeclReplacer { 27 28 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >; 28 29 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >; 30 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >; 29 31 30 32 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false ); 31 33 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false ); 32 34 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false ); 35 const Node * replace( const Node * node, const ExprMap & exprMap); 33 36 } 34 37 } -
src/AST/Expr.cpp
rbdfc032 reef8dfb 20 20 #include <vector> 21 21 22 #include "Copy.hpp" // for shallowCopy 23 #include "Eval.hpp" // for call 22 24 #include "GenericSubstitution.hpp" 25 #include "LinkageSpec.hpp" 23 26 #include "Stmt.hpp" 24 27 #include "Type.hpp" … … 27 30 #include "Common/SemanticError.h" 28 31 #include "GenPoly/Lvalue.h" // for referencesPermissable 29 #include "InitTweak/InitTweak.h" // for get PointerBase32 #include "InitTweak/InitTweak.h" // for getFunction, getPointerBase 30 33 #include "ResolvExpr/typeops.h" // for extractResultType 31 34 #include "Tuples/Tuples.h" // for makeTupleType 32 35 33 36 namespace ast { 37 38 namespace { 39 std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"}; 40 } 41 42 // --- Expr 43 bool Expr::get_lvalue() const { 44 return false; 45 } 34 46 35 47 // --- ApplicationExpr … … 46 58 } 47 59 60 bool ApplicationExpr::get_lvalue() const { 61 if ( const DeclWithType * func = InitTweak::getFunction( this ) ) { 62 return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name ); 63 } 64 return false; 65 } 66 48 67 // --- UntypedExpr 49 68 50 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) {69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) { 51 70 assert( arg ); 52 71 53 UntypedExpr * ret = new UntypedExpr{ 54 loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } } 55 }; 72 UntypedExpr * ret = call( loc, "*?", arg ); 56 73 if ( const Type * ty = arg->result ) { 57 74 const Type * base = InitTweak::getPointerBase( ty ); … … 65 82 // base type 66 83 ret->result = base; 67 add_qualifiers( ret->result, CV::Lvalue );68 84 } 69 85 } … … 71 87 } 72 88 73 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ) { 89 bool UntypedExpr::get_lvalue() const { 90 std::string fname = InitTweak::getFunctionName( this ); 91 return lvalueFunctionNames.count( fname ); 92 } 93 94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) { 74 95 assert( lhs && rhs ); 75 96 76 UntypedExpr * ret = new UntypedExpr{ 77 loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } } 78 }; 97 UntypedExpr * ret = call( loc, "?=?", lhs, rhs ); 79 98 if ( lhs->result && rhs->result ) { 80 99 // if both expressions are typed, assumes that this assignment is a C bitwise assignment, … … 83 102 } 84 103 return ret; 104 } 105 106 // --- VariableExpr 107 108 VariableExpr::VariableExpr( const CodeLocation & loc ) 109 : Expr( loc ), var( nullptr ) {} 110 111 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v ) 112 : Expr( loc ), var( v ) { 113 assert( var ); 114 assert( var->get_type() ); 115 result = shallowCopy( var->get_type() ); 116 } 117 118 bool VariableExpr::get_lvalue() const { 119 // It isn't always an lvalue, but it is never an rvalue. 120 return true; 121 } 122 123 VariableExpr * VariableExpr::functionPointer( 124 const CodeLocation & loc, const FunctionDecl * decl ) { 125 // wrap usually-determined result type in a pointer 126 VariableExpr * funcExpr = new VariableExpr{ loc, decl }; 127 funcExpr->result = new PointerType{ funcExpr->result }; 128 return funcExpr; 85 129 } 86 130 … … 108 152 AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) { 109 153 if ( arg->result ) { 110 if ( arg-> result->is_lvalue() ) {154 if ( arg->get_lvalue() ) { 111 155 // lvalue, retains all levels of reference, and gains a pointer inside the references 112 156 Type * res = addrType( arg->result ); 113 res->set_lvalue( false ); // result of & is never an lvalue114 157 result = res; 115 158 } else { … … 118 161 dynamic_cast< const ReferenceType * >( arg->result.get() ) ) { 119 162 Type * res = addrType( refType->base ); 120 res->set_lvalue( false ); // result of & is never an lvalue121 163 result = res; 122 164 } else { … … 139 181 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {} 140 182 183 bool CastExpr::get_lvalue() const { 184 // This is actually wrong by C, but it works with our current set-up. 185 return arg->get_lvalue(); 186 } 187 141 188 // --- KeywordCastExpr 142 189 143 190 const char * KeywordCastExpr::targetString() const { 144 191 return AggregateDecl::aggrString( target ); 192 } 193 194 // --- UntypedMemberExpr 195 196 bool UntypedMemberExpr::get_lvalue() const { 197 return aggregate->get_lvalue(); 145 198 } 146 199 … … 153 206 assert( aggregate->result ); 154 207 155 // take ownership of member type156 208 result = mem->get_type(); 209 157 210 // substitute aggregate generic parameters into member type 158 211 genericSubstitution( aggregate->result ).apply( result ); 159 // ensure lvalue and appropriate restrictions from aggregate type 160 add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue ); 161 } 162 163 // --- VariableExpr 164 165 VariableExpr::VariableExpr( const CodeLocation & loc ) 166 : Expr( loc ), var( nullptr ) {} 167 168 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v ) 169 : Expr( loc ), var( v ) { 170 assert( var ); 171 assert( var->get_type() ); 172 result = var->get_type(); 173 add_qualifiers( result, CV::Lvalue ); 174 } 175 176 VariableExpr * VariableExpr::functionPointer( 177 const CodeLocation & loc, const FunctionDecl * decl ) { 178 // wrap usually-determined result type in a pointer 179 VariableExpr * funcExpr = new VariableExpr{ loc, decl }; 180 funcExpr->result = new PointerType{ funcExpr->result }; 181 return funcExpr; 212 // ensure appropriate restrictions from aggregate type 213 add_qualifiers( result, aggregate->result->qualifiers ); 214 } 215 216 MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg, 217 MemberExpr::NoOpConstruction overloadSelector ) 218 : Expr( loc ), member( mem ), aggregate( agg ) { 219 assert( member ); 220 assert( aggregate ); 221 assert( aggregate->result ); 222 (void) overloadSelector; 223 } 224 225 bool MemberExpr::get_lvalue() const { 226 // This is actually wrong by C, but it works with our current set-up. 227 return true; 182 228 } 183 229 … … 258 304 : Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {} 259 305 306 // --- CommaExpr 307 bool CommaExpr::get_lvalue() const { 308 // This is wrong by C, but the current implementation uses it. 309 // (ex: Specialize, Lvalue and Box) 310 return arg2->get_lvalue(); 311 } 312 260 313 // --- ConstructorExpr 261 314 … … 276 329 assert( t && i ); 277 330 result = t; 278 add_qualifiers( result, CV::Lvalue ); 331 } 332 333 bool CompoundLiteralExpr::get_lvalue() const { 334 return true; 279 335 } 280 336 … … 293 349 // like MemberExpr, TupleIndexExpr is always an lvalue 294 350 result = type->types[ index ]; 295 add_qualifiers( result, CV::Lvalue ); 351 } 352 353 bool TupleIndexExpr::get_lvalue() const { 354 return tuple->get_lvalue(); 296 355 } 297 356 -
src/AST/Expr.hpp
rbdfc032 reef8dfb 31 31 32 32 // Must be included in *all* AST classes; should be #undef'd at the end of the file 33 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 33 #define MUTATE_FRIEND \ 34 template<typename node_t> friend node_t * mutate(const node_t * node); \ 35 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 36 34 37 35 38 class ConverterOldToNew; … … 42 45 struct ParamEntry { 43 46 UniqueId decl; 44 ptr<Decl> declptr;47 readonly<Decl> declptr; 45 48 ptr<Type> actualType; 46 49 ptr<Type> formalType; … … 62 65 class Expr : public ParseNode { 63 66 public: 64 /// Saves space (~16 bytes) by combining ResnSlots and InferredParams 67 /* 68 * NOTE: the union approach is incorrect until the case of 69 * partial resolution in InferMatcher is eliminated. 70 * it is reverted to allow unresolved and resolved parameters 71 * to coexist in an expression node. 72 */ 65 73 struct InferUnion { 74 // mode is now unused 66 75 enum { Empty, Slots, Params } mode; 67 union data_t { 68 char def; 69 ResnSlots resnSlots; 70 InferredParams inferParams; 71 72 data_t() : def('\0') {} 73 ~data_t() {} 76 struct data_t { 77 // char def; 78 ResnSlots * resnSlots; 79 InferredParams * inferParams; 80 81 data_t(): resnSlots(nullptr), inferParams(nullptr) {} 82 data_t(const data_t &other) = delete; 83 ~data_t() { 84 delete resnSlots; 85 delete inferParams; 86 } 74 87 } data; 75 88 76 89 /// initializes from other InferUnion 77 90 void init_from( const InferUnion& o ) { 78 switch ( o.mode ) { 79 case Empty: return; 80 case Slots: new(&data.resnSlots) ResnSlots{ o.data.resnSlots }; return; 81 case Params: new(&data.inferParams) InferredParams{ o.data.inferParams }; return; 91 if (o.data.resnSlots) { 92 data.resnSlots = new ResnSlots(*o.data.resnSlots); 93 } 94 if (o.data.inferParams) { 95 data.inferParams = new InferredParams(*o.data.inferParams); 82 96 } 83 97 } … … 85 99 /// initializes from other InferUnion (move semantics) 86 100 void init_from( InferUnion&& o ) { 87 switch ( o.mode ) { 88 case Empty: return; 89 case Slots: new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return; 90 case Params: 91 new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return; 92 } 93 } 94 95 /// clears variant fields 96 void reset() { 97 switch( mode ) { 98 case Empty: return; 99 case Slots: data.resnSlots.~ResnSlots(); return; 100 case Params: data.inferParams.~InferredParams(); return; 101 } 101 data.resnSlots = o.data.resnSlots; 102 data.inferParams = o.data.inferParams; 103 o.data.resnSlots = nullptr; 104 o.data.inferParams = nullptr; 102 105 } 103 106 … … 107 110 InferUnion& operator= ( const InferUnion& ) = delete; 108 111 InferUnion& operator= ( InferUnion&& ) = delete; 109 ~InferUnion() { reset(); } 112 113 bool hasSlots() const { return data.resnSlots; } 114 bool hasParams() const { return data.inferParams; } 110 115 111 116 ResnSlots& resnSlots() { 112 switch (mode) { 113 case Empty: new(&data.resnSlots) ResnSlots{}; mode = Slots; // fallthrough 114 case Slots: return data.resnSlots; 115 case Params: assertf(false, "Cannot return to resnSlots from Params"); abort(); 117 if (!data.resnSlots) { 118 data.resnSlots = new ResnSlots(); 116 119 } 117 assertf(false, "unreachable");120 return *data.resnSlots; 118 121 } 119 122 120 123 const ResnSlots& resnSlots() const { 121 if ( mode ==Slots) {122 return data.resnSlots;124 if (data.resnSlots) { 125 return *data.resnSlots; 123 126 } 124 127 assertf(false, "Mode was not already resnSlots"); … … 127 130 128 131 InferredParams& inferParams() { 129 switch (mode) { 130 case Slots: data.resnSlots.~ResnSlots(); // fallthrough 131 case Empty: new(&data.inferParams) InferredParams{}; mode = Params; // fallthrough 132 case Params: return data.inferParams; 132 if (!data.inferParams) { 133 data.inferParams = new InferredParams(); 133 134 } 134 assertf(false, "unreachable");135 return *data.inferParams; 135 136 } 136 137 137 138 const InferredParams& inferParams() const { 138 if ( mode ==Params) {139 return data.inferParams;139 if (data.inferParams) { 140 return *data.inferParams; 140 141 } 141 142 assertf(false, "Mode was not already Params"); … … 143 144 } 144 145 145 void set_inferParams( InferredParams && ps ) { 146 switch(mode) { 147 case Slots: 148 data.resnSlots.~ResnSlots(); 149 // fallthrough 150 case Empty: 151 new(&data.inferParams) InferredParams{ std::move( ps ) }; 152 mode = Params; 153 break; 154 case Params: 155 data.inferParams = std::move( ps ); 156 break; 157 } 146 void set_inferParams( InferredParams * ps ) { 147 delete data.resnSlots; 148 data.resnSlots = nullptr; 149 delete data.inferParams; 150 data.inferParams = ps; 158 151 } 159 152 … … 161 154 /// and the other is in `Params`. 162 155 void splice( InferUnion && o ) { 163 if ( o.mode == Empty ) return; 164 if ( mode == Empty ) { init_from( o ); return; } 165 assert( mode == o.mode && "attempt to splice incompatible InferUnion" ); 166 167 if ( mode == Slots ){ 168 data.resnSlots.insert( 169 data.resnSlots.end(), o.data.resnSlots.begin(), o.data.resnSlots.end() ); 170 } else if ( mode == Params ) { 171 for ( const auto & p : o.data.inferParams ) { 172 data.inferParams[p.first] = std::move(p.second); 156 if (o.data.resnSlots) { 157 if (data.resnSlots) { 158 data.resnSlots->insert( 159 data.resnSlots->end(), o.data.resnSlots->begin(), o.data.resnSlots->end() ); 160 delete o.data.resnSlots; 173 161 } 174 } else assertf(false, "invalid mode"); 162 else { 163 data.resnSlots = o.data.resnSlots; 164 } 165 o.data.resnSlots = nullptr; 166 } 167 168 if (o.data.inferParams) { 169 if (data.inferParams) { 170 for ( const auto & p : *o.data.inferParams ) { 171 (*data.inferParams)[p.first] = std::move(p.second); 172 } 173 delete o.data.inferParams; 174 } 175 else { 176 data.inferParams = o.data.inferParams; 177 } 178 o.data.inferParams = nullptr; 179 } 175 180 } 176 181 }; … … 185 190 186 191 Expr * set_extension( bool ex ) { extension = ex; return this; } 192 virtual bool get_lvalue() const; 187 193 188 194 virtual const Expr * accept( Visitor & v ) const override = 0; … … 201 207 ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ); 202 208 209 bool get_lvalue() const final; 210 203 211 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 204 212 private: … … 216 224 : Expr( loc ), func( f ), args( std::move(as) ) {} 217 225 226 bool get_lvalue() const final; 227 218 228 /// Creates a new dereference expression 219 static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg );229 static UntypedExpr * createDeref( const CodeLocation & loc, const Expr * arg ); 220 230 /// Creates a new assignment expression 221 static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs,Expr * rhs );231 static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ); 222 232 223 233 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 241 251 }; 242 252 253 /// A reference to a named variable. 254 class VariableExpr final : public Expr { 255 public: 256 readonly<DeclWithType> var; 257 258 VariableExpr( const CodeLocation & loc ); 259 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 260 261 bool get_lvalue() const final; 262 263 /// generates a function pointer for a given function 264 static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl ); 265 266 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 267 private: 268 VariableExpr * clone() const override { return new VariableExpr{ *this }; } 269 MUTATE_FRIEND 270 }; 271 243 272 /// Address-of expression `&e` 244 273 class AddressExpr final : public Expr { … … 271 300 }; 272 301 273 /// Whether a cast existed in the program source or not 302 /// Inidicates whether the cast is introduced by the CFA type system. 303 /// GeneratedCast for casts that the resolver introduces to force a return type 304 /// ExplicitCast for casts from user code 305 /// ExplicitCast for casts from desugaring advanced CFA features into simpler CFA 306 /// example 307 /// int * p; // declaration 308 /// (float *) p; // use, with subject cast 309 /// subject cast being GeneratedCast means we are considering an interpretation with a type mismatch 310 /// subject cast being ExplicitCast means someone in charge wants it that way 274 311 enum GeneratedFlag { ExplicitCast, GeneratedCast }; 275 312 … … 291 328 CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {} 292 329 330 bool get_lvalue() const final; 331 293 332 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 294 333 private: … … 301 340 public: 302 341 ptr<Expr> arg; 342 struct Concrete { 343 std::string field; 344 std::string getter; 345 346 Concrete() = default; 347 Concrete(const Concrete &) = default; 348 }; 303 349 ast::AggregateDecl::Aggregate target; 350 Concrete concrete_target; 351 304 352 305 353 KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t ) 306 354 : Expr( loc ), arg( a ), target( t ) {} 307 355 356 KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t, const Concrete & ct ) 357 : Expr( loc ), arg( a ), target( t ), concrete_target( ct ) {} 358 308 359 /// Get a name for the target type 309 360 const char * targetString() const; … … 338 389 : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); } 339 390 391 bool get_lvalue() const final; 392 340 393 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 341 394 private: … … 352 405 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg ); 353 406 407 bool get_lvalue() const final; 408 354 409 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 355 410 private: 356 411 MemberExpr * clone() const override { return new MemberExpr{ *this }; } 357 412 MUTATE_FRIEND 358 }; 359 360 /// A reference to a named variable. 361 class VariableExpr final : public Expr { 362 public: 363 readonly<DeclWithType> var; 364 365 VariableExpr( const CodeLocation & loc ); 366 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 367 368 /// generates a function pointer for a given function 369 static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl ); 370 371 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 372 private: 373 VariableExpr * clone() const override { return new VariableExpr{ *this }; } 374 MUTATE_FRIEND 413 414 // Custructor overload meant only for AST conversion 415 enum NoOpConstruction { NoOpConstructionChosen }; 416 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg, 417 NoOpConstruction overloadSelector ); 418 friend class ::ConverterOldToNew; 419 friend class ::ConverterNewToOld; 375 420 }; 376 421 … … 386 431 const CodeLocation & loc, const Type * ty, const std::string & r, 387 432 std::optional<unsigned long long> i ) 388 : Expr( loc, ty ), rep( r ), ival( i ) {}433 : Expr( loc, ty ), rep( r ), ival( i ), underlyer(ty) {} 389 434 390 435 /// Gets the integer value of this constant, if one is appropriate to its type. … … 532 577 533 578 CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 ) 534 : Expr( loc ), arg1( a1 ), arg2( a2 ) {} 579 : Expr( loc ), arg1( a1 ), arg2( a2 ) { 580 this->result = a2->result; 581 } 582 583 bool get_lvalue() const final; 535 584 536 585 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 577 626 578 627 ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call ) 579 : Expr( loc, call->result ) { assert( call); }628 : Expr( loc, call->result ), callExpr(call) { assert( call ); assert(call->result); } 580 629 581 630 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 605 654 CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i ); 606 655 656 bool get_lvalue() const final; 657 607 658 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 608 659 private: … … 660 711 661 712 TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i ); 713 714 bool get_lvalue() const final; 662 715 663 716 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 698 751 std::vector<ptr<Expr>> dtors; ///< destructor(s) for return variable(s) 699 752 753 readonly<ExprStmt> resultExpr; 754 700 755 StmtExpr( const CodeLocation & loc, const CompoundStmt * ss ); 701 756 -
src/AST/Fwd.hpp
rbdfc032 reef8dfb 10 10 // Created On : Wed May 8 16:05:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Jun 24 09:48:00 201913 // Update Count : 112 // Last Modified On : Thr Jul 23 14:15:00 2020 13 // Update Count : 2 14 14 // 15 15 … … 53 53 class CatchStmt; 54 54 class FinallyStmt; 55 class SuspendStmt; 55 56 class WaitForStmt; 56 57 class WithStmt; … … 106 107 class QualifiedType; 107 108 class FunctionType; 108 class ReferenceToType; 109 class StructInstType; 110 class UnionInstType; 111 class EnumInstType; 109 class BaseInstType; 110 template<typename decl_t> class SueInstType; 111 using StructInstType = SueInstType<StructDecl>; 112 using UnionInstType = SueInstType<UnionDecl>; 113 using EnumInstType = SueInstType<EnumDecl>; 112 114 class TraitInstType; 113 115 class TypeInstType; … … 135 137 typedef unsigned int UniqueId; 136 138 139 struct TranslationUnit; 140 // TODO: Get from the TranslationUnit: 141 extern ptr<Type> sizeType; 142 extern const FunctionDecl * dereferenceOperator; 143 extern const StructDecl * dtorStruct; 144 extern const FunctionDecl * dtorStructDestroy; 145 137 146 } -
src/AST/GenericSubstitution.cpp
rbdfc032 reef8dfb 42 42 private: 43 43 // make substitution for generic type 44 void makeSub( const ReferenceToType * ty ) {44 void makeSub( const BaseInstType * ty ) { 45 45 visit_children = false; 46 46 const AggregateDecl * aggr = ty->aggr(); … … 62 62 Pass<GenericSubstitutionBuilder> builder; 63 63 maybe_accept( ty, builder ); 64 return std::move(builder. pass.sub);64 return std::move(builder.core.sub); 65 65 } 66 66 -
src/AST/Init.hpp
rbdfc032 reef8dfb 25 25 26 26 // Must be included in *all* AST classes; should be #undef'd at the end of the file 27 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 27 #define MUTATE_FRIEND \ 28 template<typename node_t> friend node_t * mutate(const node_t * node); \ 29 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 28 30 29 31 namespace ast { … … 48 50 49 51 /// Flag for whether to construct from initialzier 50 enum ConstructFlag { DoConstruct, MaybeConstruct };52 enum ConstructFlag { NoConstruct, MaybeConstruct }; 51 53 52 54 /// Object initializer base class … … 69 71 ptr<Expr> value; 70 72 71 SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = DoConstruct )73 SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = NoConstruct ) 72 74 : Init( loc, mc ), value( val ) {} 73 75 … … 88 90 89 91 ListInit( const CodeLocation & loc, std::vector<ptr<Init>> && is, 90 std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = DoConstruct );92 std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = NoConstruct ); 91 93 92 94 using iterator = std::vector<ptr<Init>>::iterator; … … 116 118 ConstructorInit( 117 119 const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init ) 118 : Init( loc, DoConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}120 : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {} 119 121 120 122 const Init * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Node.cpp
rbdfc032 reef8dfb 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu May 16 14:16:00 2019 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Jun 5 10:21:00 2020 13 // Update Count : 1 14 14 // 15 15 … … 17 17 #include "Fwd.hpp" 18 18 19 #include <csignal> // MEMORY DEBUG -- for raise 19 20 #include <iostream> 20 21 … … 29 30 #include "Print.hpp" 30 31 31 template< typename node_t, enum ast::Node::ref_type ref_t > 32 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); } 33 34 template< typename node_t, enum ast::Node::ref_type ref_t > 35 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); } 36 37 template< typename node_t, enum ast::Node::ref_type ref_t > 38 void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); } 32 /// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object. 33 /// Process to use in GDB: 34 /// break ast::Node::_trap() 35 /// run 36 /// set variable MEM_TRAP_OBJ = <target> 37 /// disable <first breakpoint> 38 /// continue 39 void * MEM_TRAP_OBJ = nullptr; 40 41 void _trap( const void * node ) { 42 if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP); 43 } 44 45 [[noreturn]] static inline void strict_fail(const ast::Node * node) { 46 assertf(node, "strict_as had nullptr input."); 47 const ast::ParseNode * parse = dynamic_cast<const ast::ParseNode *>( node ); 48 if ( nullptr == parse ) { 49 assertf(nullptr, "%s (no location)", toString(node).c_str()); 50 } else if ( parse->location.isUnset() ) { 51 assertf(nullptr, "%s (unset location)", toString(node).c_str()); 52 } else { 53 assertf(nullptr, "%s (at %s:%d)", toString(node).c_str(), 54 parse->location.filename.c_str(), parse->location.first_line); 55 } 56 } 57 58 template< typename node_t, enum ast::Node::ref_type ref_t > 59 void ast::ptr_base<node_t, ref_t>::_strict_fail() const { 60 strict_fail(node); 61 } 62 63 template< typename node_t, enum ast::Node::ref_type ref_t > 64 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { 65 node->increment(ref_t); 66 _trap( node ); 67 } 68 69 template< typename node_t, enum ast::Node::ref_type ref_t > 70 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) { 71 _trap( node ); 72 node->decrement( ref_t, do_delete ); 73 } 74 75 template< typename node_t, enum ast::Node::ref_type ref_t > 76 void ast::ptr_base<node_t, ref_t>::_check() const { 77 // if(node) assert(node->was_ever_strong == false || node->strong_count > 0); 78 } 39 79 40 80 template< typename node_t, enum ast::Node::ref_type ref_t > … … 226 266 template class ast::ptr_base< ast::FunctionType, ast::Node::ref_type::weak >; 227 267 template class ast::ptr_base< ast::FunctionType, ast::Node::ref_type::strong >; 228 template class ast::ptr_base< ast:: ReferenceToType, ast::Node::ref_type::weak >;229 template class ast::ptr_base< ast:: ReferenceToType, ast::Node::ref_type::strong >;268 template class ast::ptr_base< ast::BaseInstType, ast::Node::ref_type::weak >; 269 template class ast::ptr_base< ast::BaseInstType, ast::Node::ref_type::strong >; 230 270 template class ast::ptr_base< ast::StructInstType, ast::Node::ref_type::weak >; 231 271 template class ast::ptr_base< ast::StructInstType, ast::Node::ref_type::strong >; -
src/AST/Node.hpp
rbdfc032 reef8dfb 10 10 // Created On : Wed May 8 10:27:04 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Jun 3 13:26:00 201913 // Update Count : 512 // Last Modified On : Fri Jun 5 9:47:00 2020 13 // Update Count : 6 14 14 // 15 15 … … 38 38 Node& operator= (const Node&) = delete; 39 39 Node& operator= (Node&&) = delete; 40 virtual ~Node() = default;40 virtual ~Node() {} 41 41 42 42 virtual const Node * accept( Visitor & v ) const = 0; … … 49 49 50 50 bool unique() const { return strong_count == 1; } 51 bool isManaged() const {return strong_count > 0; } 51 52 52 53 private: … … 57 58 template<typename node_t> 58 59 friend node_t * mutate(const node_t * node); 60 template<typename node_t> 61 friend node_t * shallowCopy(const node_t * node); 59 62 60 63 mutable size_t strong_count = 0; … … 69 72 } 70 73 71 void decrement(ast::Node::ref_type ref ) const {74 void decrement(ast::Node::ref_type ref, bool do_delete = true) const { 72 75 switch (ref) { 73 76 case ref_type::strong: strong_count--; break; … … 75 78 } 76 79 77 if( !strong_count && !weak_count) {80 if( do_delete && !strong_count && !weak_count) { 78 81 delete this; 79 82 } … … 94 97 assertf( 95 98 node->weak_count == 0, 96 "Error: mutating node with weak references to it will invalid edsome references"99 "Error: mutating node with weak references to it will invalidate some references" 97 100 ); 98 101 return node->clone(); … … 104 107 // skip mutate if equivalent 105 108 if ( node->*field == val ) return node; 106 109 107 110 // mutate and return 108 111 node_t * ret = mutate( node ); … … 123 126 (ret->*field)[i] = std::forward< field_t >( val ); 124 127 return ret; 128 } 129 130 /// Mutate an entire indexed collection by cloning to accepted value 131 template<typename node_t, typename parent_t, typename coll_t> 132 const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) { 133 for ( unsigned i = 0; i < (node->*field).size(); ++i ) { 134 node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) ); 135 } 136 return node; 125 137 } 126 138 … … 217 229 const node_t & operator* () const { _check(); return *node; } 218 230 explicit operator bool() const { _check(); return node; } 219 operator const node_t * () const { _check(); return node; } 231 operator const node_t * () const & { _check(); return node; } 232 operator const node_t * () && = delete; 233 234 const node_t * release() { 235 const node_t * ret = node; 236 if ( node ) { 237 _dec(node, false); 238 node = nullptr; 239 } 240 return ret; 241 } 220 242 221 243 /// wrapper for convenient access to dynamic_cast … … 223 245 const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); } 224 246 225 /// wrapper for convenient access to strict_dynamic_cast247 /// Wrapper that makes sure dynamic_cast returns non-null. 226 248 template<typename o_node_t> 227 const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); } 249 const o_node_t * strict_as() const { 250 if (const o_node_t * ret = as<o_node_t>()) return ret; 251 _strict_fail(); 252 } 253 254 /// Wrapper that makes sure dynamic_cast does not fail. 255 template<typename o_node_t, decltype(nullptr) null> 256 const o_node_t * strict_as() const { return node ? strict_as<o_node_t>() : nullptr; } 228 257 229 258 /// Returns a mutable version of the pointer in this node. … … 244 273 245 274 void _inc( const node_t * other ); 246 void _dec( const node_t * other );275 void _dec( const node_t * other, bool do_delete = true ); 247 276 void _check() const; 277 void _strict_fail() const __attribute__((noreturn)); 248 278 249 279 const node_t * node; -
src/AST/Pass.hpp
rbdfc032 reef8dfb 8 8 // 9 9 // Author : Thierry Delisle 10 // Created On : Thu May 09 15: :37::05 201910 // Created On : Thu May 09 15:37:05 2019 11 11 // Last Modified By : 12 12 // Last Modified On : … … 46 46 // 47 47 // Several additional features are available through inheritance 48 // | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the 49 // current expression 50 // | WithStmtsToAdd - provides the ability to insert statements before or after the current 51 // statement by adding new statements into stmtsToAddBefore or 52 // stmtsToAddAfter respectively. 53 // | WithDeclsToAdd - provides the ability to insert declarations before or after the current 54 // declarations by adding new DeclStmt into declsToAddBefore or 55 // declsToAddAfter respectively. 56 // | WithShortCircuiting - provides the ability to skip visiting child nodes; set visit_children 57 // to false in pre{visit,visit} to skip visiting children 58 // | WithGuards - provides the ability to save/restore data like a LIFO stack; to save, 59 // call GuardValue with the variable to save, the variable will 60 // automatically be restored to its previous value after the corresponding 61 // postvisit/postmutate teminates. 62 // | WithVisitorRef - provides an pointer to the templated visitor wrapper 63 // | WithSymbolTable - provides symbol table functionality 48 // | PureVisitor - makes the visitor pure, it never modifies nodes in place and always 49 // clones nodes it needs to make changes to 50 // | WithConstTypeSubstitution - provides polymorphic const TypeSubstitution * typeSubs for the 51 // current expression 52 // | WithStmtsToAdd - provides the ability to insert statements before or after the current 53 // statement by adding new statements into stmtsToAddBefore or 54 // stmtsToAddAfter respectively. 55 // | WithDeclsToAdd - provides the ability to insert declarations before or after the 56 // current declarations by adding new DeclStmt into declsToAddBefore or 57 // declsToAddAfter respectively. 58 // | WithShortCircuiting - provides the ability to skip visiting child nodes; set visit_children 59 // to false in pre{visit,visit} to skip visiting children 60 // | WithGuards - provides the ability to save/restore data like a LIFO stack; to save, 61 // call GuardValue with the variable to save, the variable will 62 // automatically be restored to its previous value after the 63 // corresponding postvisit/postmutate teminates. 64 // | WithVisitorRef - provides an pointer to the templated visitor wrapper 65 // | WithSymbolTable - provides symbol table functionality 66 // 67 // Other Special Members: 68 // | result - Either a method that takes no parameters or a field. If a method (or 69 // callable field) get_result calls it, otherwise the value is returned. 64 70 //------------------------------------------------------------------------------------------------- 65 template< typename pass_t >71 template< typename core_t > 66 72 class Pass final : public ast::Visitor { 67 73 public: 74 using core_type = core_t; 75 using type = Pass<core_t>; 76 68 77 /// Forward any arguments to the pass constructor 69 78 /// Propagate 'this' if necessary 70 79 template< typename... Args > 71 80 Pass( Args &&... args) 72 : pass( std::forward<Args>( args )... )81 : core( std::forward<Args>( args )... ) 73 82 { 74 83 // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor 75 typedef Pass<pass_t> this_t; 76 this_t * const * visitor = __pass::visitor(pass, 0); 84 type * const * visitor = __pass::visitor(core, 0); 77 85 if(visitor) { 78 *const_cast<t his_t**>( visitor ) = this;86 *const_cast<type **>( visitor ) = this; 79 87 } 80 88 } … … 82 90 virtual ~Pass() = default; 83 91 84 /// Storage for the actual pass 85 pass_t pass; 92 /// Storage for the actual pass. 93 core_t core; 94 95 /// If the core defines a result, call it if possible, otherwise return it. 96 inline auto get_result() -> decltype( __pass::get_result( core, '0' ) ) { 97 return __pass::get_result( core, '0' ); 98 } 99 100 /// Construct and run a pass on a translation unit. 101 template< typename... Args > 102 static void run( TranslationUnit & decls, Args &&... args ) { 103 Pass<core_t> visitor( std::forward<Args>( args )... ); 104 accept_all( decls, visitor ); 105 } 106 107 /// Contruct and run a pass on a pointer to extract a value. 108 template< typename node_type, typename... Args > 109 static auto read( node_type const * node, Args&&... args ) { 110 Pass<core_t> visitor( std::forward<Args>( args )... ); 111 node_type const * temp = node->accept( visitor ); 112 assert( temp == node ); 113 return visitor.get_result(); 114 } 115 116 // Versions of the above for older compilers. 117 template< typename... Args > 118 static void run( TranslationUnit & decls ) { 119 Pass<core_t> visitor; 120 accept_all( decls, visitor ); 121 } 122 123 template< typename node_type, typename... Args > 124 static auto read( node_type const * node ) { 125 Pass<core_t> visitor; 126 node_type const * temp = node->accept( visitor ); 127 assert( temp == node ); 128 return visitor.get_result(); 129 } 86 130 87 131 /// Visit function declarations … … 111 155 const ast::Stmt * visit( const ast::CatchStmt * ) override final; 112 156 const ast::Stmt * visit( const ast::FinallyStmt * ) override final; 157 const ast::Stmt * visit( const ast::SuspendStmt * ) override final; 113 158 const ast::Stmt * visit( const ast::WaitForStmt * ) override final; 114 159 const ast::Decl * visit( const ast::WithStmt * ) override final; … … 178 223 const ast::TypeSubstitution * visit( const ast::TypeSubstitution * ) override final; 179 224 180 template<typename pass_type> 181 friend void accept_all( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor ); 225 template<typename core_type> 226 friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor ); 227 228 bool isInFunction() const { 229 return inFunction; 230 } 231 182 232 private: 183 233 184 bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children( pass, 0); return ptr ? *ptr : true; }234 bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; } 185 235 186 236 private: 187 237 const ast::Stmt * call_accept( const ast::Stmt * ); 188 238 const ast::Expr * call_accept( const ast::Expr * ); 239 240 // requests WithStmtsToAdd directly add to this statement, as if it is a compound. 241 242 const ast::Stmt * call_accept_as_compound(const ast::Stmt *); 189 243 190 244 template< typename node_t > … … 206 260 void maybe_accept(const node_t * &, child_t parent_t::* child); 207 261 262 template<typename node_t, typename parent_t, typename child_t> 263 void maybe_accept_as_compound(const node_t * &, child_t parent_t::* child); 264 208 265 private: 209 266 /// Internal RAII guard for symbol table features 210 267 struct guard_symtab { 211 guard_symtab( Pass< pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }212 ~guard_symtab() { __pass::symtab::leave(pass , 0); }213 Pass< pass_t> & pass;268 guard_symtab( Pass<core_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.core, 0); } 269 ~guard_symtab() { __pass::symtab::leave(pass.core, 0); } 270 Pass<core_t> & pass; 214 271 }; 215 272 216 273 /// Internal RAII guard for scope features 217 274 struct guard_scope { 218 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); } 219 ~guard_scope() { __pass::scope::leave(pass, 0); } 220 Pass<pass_t> & pass; 275 guard_scope( Pass<core_t> & pass ): pass( pass ) { __pass::scope::enter(pass.core, 0); } 276 ~guard_scope() { __pass::scope::leave(pass.core, 0); } 277 Pass<core_t> & pass; 278 }; 279 280 /// Internal RAII guard for forall substitutions 281 struct guard_forall_subs { 282 guard_forall_subs( Pass<core_t> & pass, const FunctionType * type ) 283 : pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); } 284 ~guard_forall_subs() { __pass::forall::leave(pass.core, 0, type ); } 285 Pass<core_t> & pass; 286 const FunctionType * type; 221 287 }; 222 288 223 289 private: 224 290 bool inFunction = false; 291 bool atFunctionTop = false; 225 292 }; 226 293 227 294 /// Apply a pass to an entire translation unit 228 template<typename pass_t> 229 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor ); 295 template<typename core_t> 296 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor ); 297 298 template<typename core_t> 299 void accept_all( ast::TranslationUnit &, ast::Pass<core_t> & visitor ); 230 300 231 301 //------------------------------------------------------------------------------------------------- … … 233 303 //------------------------------------------------------------------------------------------------- 234 304 235 /// Keep track of the polymorphic const TypeSubstitution * env for the current expression 305 /// If used the visitor will always clone nodes. 306 struct PureVisitor {}; 307 308 /// Keep track of the polymorphic const TypeSubstitution * typeSubs for the current expression. 236 309 struct WithConstTypeSubstitution { 237 const TypeSubstitution * env= nullptr;310 const TypeSubstitution * typeSubs = nullptr; 238 311 }; 239 312 … … 267 340 }; 268 341 269 template< typename pass_t>270 friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );342 template< typename core_t> 343 friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup ); 271 344 public: 272 345 … … 304 377 305 378 /// Used to get a pointer to the pass with its wrapped type 306 template<typename pass_t>379 template<typename core_t> 307 380 struct WithVisitorRef { 308 Pass<pass_t> * const visitor = nullptr; 381 Pass<core_t> * const visitor = nullptr; 382 383 bool isInFunction() const { 384 return visitor->isInFunction(); 385 } 309 386 }; 310 387 … … 313 390 SymbolTable symtab; 314 391 }; 392 315 393 } 316 394 … … 320 398 extern struct PassVisitorStats { 321 399 size_t depth = 0; 322 Stats::Counters::MaxCounter<double> * max = nullptr;323 Stats::Counters::AverageCounter<double> * avg = nullptr;400 Stats::Counters::MaxCounter<double> * max; 401 Stats::Counters::AverageCounter<double> * avg; 324 402 } pass_visitor_stats; 325 403 } -
src/AST/Pass.impl.hpp
rbdfc032 reef8dfb 20 20 #include <unordered_map> 21 21 22 #include "AST/TranslationUnit.hpp" 22 23 #include "AST/TypeSubstitution.hpp" 23 24 … … 25 26 using namespace ast; \ 26 27 /* back-up the visit children */ \ 27 __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children( pass, 0) ); \28 __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \ 28 29 /* setup the scope for passes that want to run code at exit */ \ 29 __attribute__((unused)) ast::__pass::guard_value guard2( ast::__pass::at_cleanup (pass, 0) ); \ 30 __attribute__((unused)) ast::__pass::guard_value guard2( ast::__pass::at_cleanup (core, 0) ); \ 31 /* begin tracing memory allocation if requested by this pass */ \ 32 __pass::beginTrace( core, 0 ); \ 30 33 /* call the implementation of the previsit of this pass */ \ 31 __pass::previsit( pass, node, 0 );34 __pass::previsit( core, node, 0 ); 32 35 33 36 #define VISIT( code... ) \ … … 40 43 #define VISIT_END( type, node ) \ 41 44 /* call the implementation of the postvisit of this pass */ \ 42 auto __return = __pass::postvisit( pass, node, 0 ); \45 auto __return = __pass::postvisit( core, node, 0 ); \ 43 46 assertf(__return, "post visit should never return null"); \ 47 /* end tracing memory allocation if requested by this pass */ \ 48 __pass::endTrace( core, 0 ); \ 44 49 return __return; 45 50 … … 53 58 54 59 namespace ast { 60 template<typename node_t> 61 node_t * shallowCopy( const node_t * node ); 62 55 63 namespace __pass { 56 64 // Check if this is either a null pointer or a pointer to an empty container … … 60 68 } 61 69 70 template< typename core_t, typename node_t > 71 static inline node_t* mutate(const node_t *node) { 72 return std::is_base_of<PureVisitor, core_t>::value ? ::ast::shallowCopy(node) : ::ast::mutate(node); 73 } 74 62 75 //------------------------------ 63 76 template<typename it_t, template <class...> class container_t> … … 119 132 } 120 133 121 template< typename pass_t >134 template< typename core_t > 122 135 template< typename node_t > 123 auto ast::Pass< pass_t >::call_accept( const node_t * node )136 auto ast::Pass< core_t >::call_accept( const node_t * node ) 124 137 -> typename std::enable_if< 125 138 !std::is_base_of<ast::Expr, node_t>::value && … … 127 140 , decltype( node->accept(*this) ) 128 141 >::type 129 130 142 { 131 143 __pedantic_pass_assert( __visit_children() ); 132 __pedantic_pass_assert( expr);144 __pedantic_pass_assert( node ); 133 145 134 146 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR"); … … 138 150 } 139 151 140 template< typename pass_t >141 const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {152 template< typename core_t > 153 const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) { 142 154 __pedantic_pass_assert( __visit_children() ); 143 155 __pedantic_pass_assert( expr ); 144 156 145 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);146 if ( env_ptr && expr->env ) {147 * env_ptr = expr->env;157 const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 ); 158 if ( typeSubs_ptr && expr->env ) { 159 *typeSubs_ptr = expr->env; 148 160 } 149 161 … … 151 163 } 152 164 153 template< typename pass_t >154 const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {165 template< typename core_t > 166 const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) { 155 167 __pedantic_pass_assert( __visit_children() ); 156 168 __pedantic_pass_assert( stmt ); 157 169 170 return stmt->accept( *this ); 171 } 172 173 template< typename core_t > 174 const ast::Stmt * ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) { 175 __pedantic_pass_assert( __visit_children() ); 176 __pedantic_pass_assert( stmt ); 177 158 178 // add a few useful symbols to the scope 159 179 using __pass::empty; 160 180 161 181 // get the stmts/decls that will need to be spliced in 162 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);163 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);164 auto decls_before = __pass::declsToAddBefore( pass, 0);165 auto decls_after = __pass::declsToAddAfter ( pass, 0);182 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 183 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 184 auto decls_before = __pass::declsToAddBefore( core, 0); 185 auto decls_after = __pass::declsToAddAfter ( core, 0); 166 186 167 187 // These may be modified by subnode but most be restored once we exit this statemnet. 168 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass:: env( pass, 0) );188 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::typeSubs( core, 0 ) ); 169 189 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 170 190 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); … … 202 222 } 203 223 204 template< typename pass_t >224 template< typename core_t > 205 225 template< template <class...> class container_t > 206 container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {226 container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 207 227 __pedantic_pass_assert( __visit_children() ); 208 228 if( statements.empty() ) return {}; … … 215 235 216 236 // get the stmts/decls that will need to be spliced in 217 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);218 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);219 auto decls_before = __pass::declsToAddBefore( pass, 0);220 auto decls_after = __pass::declsToAddAfter ( pass, 0);237 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 238 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 239 auto decls_before = __pass::declsToAddBefore( core, 0); 240 auto decls_after = __pass::declsToAddAfter ( core, 0); 221 241 222 242 // These may be modified by subnode but most be restored once we exit this statemnet. … … 268 288 } 269 289 270 template< typename pass_t >290 template< typename core_t > 271 291 template< template <class...> class container_t, typename node_t > 272 container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {292 container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 273 293 __pedantic_pass_assert( __visit_children() ); 274 294 if( container.empty() ) return {}; … … 299 319 } 300 320 301 template< typename pass_t >321 template< typename core_t > 302 322 template<typename node_t, typename parent_t, typename child_t> 303 void ast::Pass< pass_t >::maybe_accept(323 void ast::Pass< core_t >::maybe_accept( 304 324 const node_t * & parent, 305 325 child_t parent_t::*child … … 317 337 318 338 if( __pass::differs(old_val, new_val) ) { 319 auto new_parent = mutate(parent); 339 auto new_parent = __pass::mutate<core_t>(parent); 340 new_parent->*child = new_val; 341 parent = new_parent; 342 } 343 } 344 345 template< typename core_t > 346 template<typename node_t, typename parent_t, typename child_t> 347 void ast::Pass< core_t >::maybe_accept_as_compound( 348 const node_t * & parent, 349 child_t parent_t::*child 350 ) { 351 static_assert( std::is_base_of<parent_t, node_t>::value, "Error deducing member object" ); 352 353 if(__pass::skip(parent->*child)) return; 354 const auto & old_val = __pass::get(parent->*child, 0); 355 356 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 357 358 auto new_val = call_accept_as_compound( old_val ); 359 360 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR"); 361 362 if( __pass::differs(old_val, new_val) ) { 363 auto new_parent = __pass::mutate<core_t>(parent); 320 364 new_parent->*child = new_val; 321 365 parent = new_parent; … … 333 377 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 334 378 335 template< typename pass_t >336 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {379 template< typename core_t > 380 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) { 337 381 // We are going to aggregate errors for all these statements 338 382 SemanticErrorException errors; … … 342 386 343 387 // get the stmts/decls that will need to be spliced in 344 auto decls_before = __pass::declsToAddBefore( visitor. pass, 0);345 auto decls_after = __pass::declsToAddAfter ( visitor. pass, 0);388 auto decls_before = __pass::declsToAddBefore( visitor.core, 0); 389 auto decls_after = __pass::declsToAddAfter ( visitor.core, 0); 346 390 347 391 // update pass statitistics … … 363 407 } 364 408 catch( SemanticErrorException &e ) { 365 errors.append( e ); 409 if (__pass::on_error (visitor.core, *i, 0)) 410 errors.append( e ); 366 411 } 367 412 … … 371 416 pass_visitor_stats.depth--; 372 417 if ( !errors.isEmpty() ) { throw errors; } 418 } 419 420 template< typename core_t > 421 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) { 422 return ast::accept_all( unit.decls, visitor ); 373 423 } 374 424 … … 392 442 //-------------------------------------------------------------------------- 393 443 // ObjectDecl 394 template< typename pass_t >395 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {444 template< typename core_t > 445 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) { 396 446 VISIT_START( node ); 397 447 … … 406 456 ) 407 457 408 __pass::symtab::addId( pass, 0, node );458 __pass::symtab::addId( core, 0, node ); 409 459 410 460 VISIT_END( DeclWithType, node ); … … 413 463 //-------------------------------------------------------------------------- 414 464 // FunctionDecl 415 template< typename pass_t >416 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {417 VISIT_START( node ); 418 419 __pass::symtab::addId( pass, 0, node );465 template< typename core_t > 466 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) { 467 VISIT_START( node ); 468 469 __pass::symtab::addId( core, 0, node ); 420 470 421 471 VISIT(maybe_accept( node, &FunctionDecl::withExprs );) … … 425 475 // shadow with exprs and not the other way around. 426 476 guard_symtab guard { *this }; 427 __pass::symtab::addWith( pass, 0, node->withExprs, node );477 __pass::symtab::addWith( core, 0, node->withExprs, node ); 428 478 { 429 479 guard_symtab guard { *this }; 430 480 // implicit add __func__ identifier as specified in the C manual 6.4.2.2 431 static ast:: ObjectDecl func(432 node->location, "__func__",433 new ast::ArrayType (434 new ast::BasicType ( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),481 static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{ 482 CodeLocation{}, "__func__", 483 new ast::ArrayType{ 484 new ast::BasicType{ ast::BasicType::Char, ast::CV::Const }, 435 485 nullptr, VariableLen, DynamicDim 436 )437 );438 __pass::symtab::addId( pass, 0, &func );486 } 487 } }; 488 __pass::symtab::addId( core, 0, func ); 439 489 VISIT( 440 maybe_accept( node, &FunctionDecl::type ); 441 // function body needs to have the same scope as parameters - CompoundStmt will not enter 442 // a new scope if inFunction is true 490 // parameter declarations 491 maybe_accept( node, &FunctionDecl::params ); 492 maybe_accept( node, &FunctionDecl::returns ); 493 // type params and assertions 494 maybe_accept( node, &FunctionDecl::type_params ); 495 maybe_accept( node, &FunctionDecl::assertions ); 496 // First remember that we are now within a function. 443 497 ValueGuard< bool > oldInFunction( inFunction ); 444 498 inFunction = true; 499 // The function body needs to have the same scope as parameters. 500 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 501 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 502 atFunctionTop = true; 445 503 maybe_accept( node, &FunctionDecl::stmts ); 446 504 maybe_accept( node, &FunctionDecl::attributes ); … … 454 512 //-------------------------------------------------------------------------- 455 513 // StructDecl 456 template< typename pass_t >457 const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {514 template< typename core_t > 515 const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) { 458 516 VISIT_START( node ); 459 517 460 518 // make up a forward declaration and add it before processing the members 461 519 // needs to be on the heap because addStruct saves the pointer 462 __pass::symtab::addStructFwd( pass, 0, node );520 __pass::symtab::addStructFwd( core, 0, node ); 463 521 464 522 VISIT({ … … 469 527 470 528 // this addition replaces the forward declaration 471 __pass::symtab::addStruct( pass, 0, node );529 __pass::symtab::addStruct( core, 0, node ); 472 530 473 531 VISIT_END( Decl, node ); … … 476 534 //-------------------------------------------------------------------------- 477 535 // UnionDecl 478 template< typename pass_t >479 const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {536 template< typename core_t > 537 const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) { 480 538 VISIT_START( node ); 481 539 482 540 // make up a forward declaration and add it before processing the members 483 __pass::symtab::addUnionFwd( pass, 0, node );541 __pass::symtab::addUnionFwd( core, 0, node ); 484 542 485 543 VISIT({ … … 489 547 }) 490 548 491 __pass::symtab::addUnion( pass, 0, node );549 __pass::symtab::addUnion( core, 0, node ); 492 550 493 551 VISIT_END( Decl, node ); … … 496 554 //-------------------------------------------------------------------------- 497 555 // EnumDecl 498 template< typename pass_t >499 const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {500 VISIT_START( node ); 501 502 __pass::symtab::addEnum( pass, 0, node );556 template< typename core_t > 557 const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) { 558 VISIT_START( node ); 559 560 __pass::symtab::addEnum( core, 0, node ); 503 561 504 562 VISIT( … … 513 571 //-------------------------------------------------------------------------- 514 572 // TraitDecl 515 template< typename pass_t >516 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {573 template< typename core_t > 574 const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) { 517 575 VISIT_START( node ); 518 576 … … 523 581 }) 524 582 525 __pass::symtab::addTrait( pass, 0, node );583 __pass::symtab::addTrait( core, 0, node ); 526 584 527 585 VISIT_END( Decl, node ); … … 530 588 //-------------------------------------------------------------------------- 531 589 // TypeDecl 532 template< typename pass_t >533 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {590 template< typename core_t > 591 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) { 534 592 VISIT_START( node ); 535 593 536 594 VISIT({ 537 595 guard_symtab guard { *this }; 538 maybe_accept( node, &TypeDecl::params );539 596 maybe_accept( node, &TypeDecl::base ); 540 597 }) … … 543 600 // note that assertions come after the type is added to the symtab, since they are not part of the type proper 544 601 // and may depend on the type itself 545 __pass::symtab::addType( pass, 0, node );602 __pass::symtab::addType( core, 0, node ); 546 603 547 604 VISIT( … … 559 616 //-------------------------------------------------------------------------- 560 617 // TypedefDecl 561 template< typename pass_t >562 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {618 template< typename core_t > 619 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) { 563 620 VISIT_START( node ); 564 621 565 622 VISIT({ 566 623 guard_symtab guard { *this }; 567 maybe_accept( node, &TypedefDecl::params );568 624 maybe_accept( node, &TypedefDecl::base ); 569 625 }) 570 626 571 __pass::symtab::addType( pass, 0, node );627 __pass::symtab::addType( core, 0, node ); 572 628 573 629 VISIT( maybe_accept( node, &TypedefDecl::assertions ); ) … … 578 634 //-------------------------------------------------------------------------- 579 635 // AsmDecl 580 template< typename pass_t >581 const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {636 template< typename core_t > 637 const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) { 582 638 VISIT_START( node ); 583 639 … … 591 647 //-------------------------------------------------------------------------- 592 648 // StaticAssertDecl 593 template< typename pass_t >594 const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {649 template< typename core_t > 650 const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) { 595 651 VISIT_START( node ); 596 652 … … 605 661 //-------------------------------------------------------------------------- 606 662 // CompoundStmt 607 template< typename pass_t > 608 const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) { 609 VISIT_START( node ); 610 VISIT({ 611 // do not enter a new scope if inFunction is true - needs to check old state before the assignment 612 auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() { 613 if ( ! inFunction ) __pass::symtab::enter(pass, 0); 614 }, [this, inFunction = this->inFunction]() { 615 if ( ! inFunction ) __pass::symtab::leave(pass, 0); 663 template< typename core_t > 664 const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) { 665 VISIT_START( node ); 666 VISIT( 667 // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result. 668 auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() { 669 if ( enterScope ) { 670 __pass::symtab::enter(core, 0); 671 __pass::scope::enter(core, 0); 672 } 673 }, [this, leaveScope = !this->atFunctionTop]() { 674 if ( leaveScope ) { 675 __pass::symtab::leave(core, 0); 676 __pass::scope::leave(core, 0); 677 } 616 678 }); 617 ValueGuard< bool > guard2( inFunction ); 679 ValueGuard< bool > guard2( atFunctionTop ); 680 atFunctionTop = false; 618 681 guard_scope guard3 { *this }; 619 inFunction = false;620 682 maybe_accept( node, &CompoundStmt::kids ); 621 })683 ) 622 684 VISIT_END( CompoundStmt, node ); 623 685 } … … 625 687 //-------------------------------------------------------------------------- 626 688 // ExprStmt 627 template< typename pass_t >628 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {689 template< typename core_t > 690 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) { 629 691 VISIT_START( node ); 630 692 … … 638 700 //-------------------------------------------------------------------------- 639 701 // AsmStmt 640 template< typename pass_t >641 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {702 template< typename core_t > 703 const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) { 642 704 VISIT_START( node ) 643 705 … … 654 716 //-------------------------------------------------------------------------- 655 717 // DirectiveStmt 656 template< typename pass_t >657 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {718 template< typename core_t > 719 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) { 658 720 VISIT_START( node ) 659 721 … … 663 725 //-------------------------------------------------------------------------- 664 726 // IfStmt 665 template< typename pass_t >666 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {727 template< typename core_t > 728 const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) { 667 729 VISIT_START( node ); 668 730 … … 672 734 maybe_accept( node, &IfStmt::inits ); 673 735 maybe_accept( node, &IfStmt::cond ); 674 maybe_accept ( node, &IfStmt::thenPart );675 maybe_accept ( node, &IfStmt::elsePart );736 maybe_accept_as_compound( node, &IfStmt::thenPart ); 737 maybe_accept_as_compound( node, &IfStmt::elsePart ); 676 738 }) 677 739 … … 681 743 //-------------------------------------------------------------------------- 682 744 // WhileStmt 683 template< typename pass_t >684 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {745 template< typename core_t > 746 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) { 685 747 VISIT_START( node ); 686 748 … … 690 752 maybe_accept( node, &WhileStmt::inits ); 691 753 maybe_accept( node, &WhileStmt::cond ); 692 maybe_accept ( node, &WhileStmt::body );754 maybe_accept_as_compound( node, &WhileStmt::body ); 693 755 }) 694 756 … … 698 760 //-------------------------------------------------------------------------- 699 761 // ForStmt 700 template< typename pass_t >701 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {762 template< typename core_t > 763 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) { 702 764 VISIT_START( node ); 703 765 … … 705 767 // for statements introduce a level of scope (for the initialization) 706 768 guard_symtab guard { *this }; 769 // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later. 707 770 maybe_accept( node, &ForStmt::inits ); 708 771 maybe_accept( node, &ForStmt::cond ); 709 772 maybe_accept( node, &ForStmt::inc ); 710 maybe_accept ( node, &ForStmt::body );773 maybe_accept_as_compound( node, &ForStmt::body ); 711 774 }) 712 775 … … 716 779 //-------------------------------------------------------------------------- 717 780 // SwitchStmt 718 template< typename pass_t >719 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {781 template< typename core_t > 782 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) { 720 783 VISIT_START( node ); 721 784 … … 730 793 //-------------------------------------------------------------------------- 731 794 // CaseStmt 732 template< typename pass_t >733 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {795 template< typename core_t > 796 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) { 734 797 VISIT_START( node ); 735 798 … … 744 807 //-------------------------------------------------------------------------- 745 808 // BranchStmt 746 template< typename pass_t >747 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {809 template< typename core_t > 810 const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) { 748 811 VISIT_START( node ); 749 812 VISIT_END( Stmt, node ); … … 752 815 //-------------------------------------------------------------------------- 753 816 // ReturnStmt 754 template< typename pass_t >755 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {817 template< typename core_t > 818 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) { 756 819 VISIT_START( node ); 757 820 … … 765 828 //-------------------------------------------------------------------------- 766 829 // ThrowStmt 767 template< typename pass_t >768 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {830 template< typename core_t > 831 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) { 769 832 VISIT_START( node ); 770 833 … … 779 842 //-------------------------------------------------------------------------- 780 843 // TryStmt 781 template< typename pass_t >782 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {844 template< typename core_t > 845 const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) { 783 846 VISIT_START( node ); 784 847 … … 794 857 //-------------------------------------------------------------------------- 795 858 // CatchStmt 796 template< typename pass_t >797 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {859 template< typename core_t > 860 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) { 798 861 VISIT_START( node ); 799 862 … … 803 866 maybe_accept( node, &CatchStmt::decl ); 804 867 maybe_accept( node, &CatchStmt::cond ); 805 maybe_accept ( node, &CatchStmt::body );868 maybe_accept_as_compound( node, &CatchStmt::body ); 806 869 }) 807 870 … … 811 874 //-------------------------------------------------------------------------- 812 875 // FinallyStmt 813 template< typename pass_t >814 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {876 template< typename core_t > 877 const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) { 815 878 VISIT_START( node ); 816 879 … … 823 886 824 887 //-------------------------------------------------------------------------- 888 // FinallyStmt 889 template< typename core_t > 890 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) { 891 VISIT_START( node ); 892 893 VISIT( 894 maybe_accept( node, &SuspendStmt::then ); 895 ) 896 897 VISIT_END( Stmt, node ); 898 } 899 900 //-------------------------------------------------------------------------- 825 901 // WaitForStmt 826 template< typename pass_t >827 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {902 template< typename core_t > 903 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) { 828 904 VISIT_START( node ); 829 905 // for( auto & clause : node->clauses ) { … … 862 938 863 939 if(mutated) { 864 auto n = mutate(node);940 auto n = __pass::mutate<core_t>(node); 865 941 n->clauses = std::move( new_clauses ); 866 942 node = n; … … 872 948 auto nval = call_accept( node->field ); \ 873 949 if(nval != node->field ) { \ 874 auto nparent = mutate(node); \950 auto nparent = __pass::mutate<core_t>(node); \ 875 951 nparent->field = nval; \ 876 952 node = nparent; \ … … 893 969 //-------------------------------------------------------------------------- 894 970 // WithStmt 895 template< typename pass_t >896 const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {971 template< typename core_t > 972 const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) { 897 973 VISIT_START( node ); 898 974 … … 902 978 // catch statements introduce a level of scope (for the caught exception) 903 979 guard_symtab guard { *this }; 904 __pass::symtab::addWith( pass, 0, node->exprs, node );980 __pass::symtab::addWith( core, 0, node->exprs, node ); 905 981 maybe_accept( node, &WithStmt::stmt ); 906 982 } … … 911 987 //-------------------------------------------------------------------------- 912 988 // NullStmt 913 template< typename pass_t >914 const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {989 template< typename core_t > 990 const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) { 915 991 VISIT_START( node ); 916 992 VISIT_END( NullStmt, node ); … … 919 995 //-------------------------------------------------------------------------- 920 996 // DeclStmt 921 template< typename pass_t >922 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {997 template< typename core_t > 998 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) { 923 999 VISIT_START( node ); 924 1000 … … 932 1008 //-------------------------------------------------------------------------- 933 1009 // ImplicitCtorDtorStmt 934 template< typename pass_t >935 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {1010 template< typename core_t > 1011 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) { 936 1012 VISIT_START( node ); 937 1013 938 1014 // For now this isn't visited, it is unclear if this causes problem 939 1015 // if all tests are known to pass, remove this code 940 //VISIT(941 //maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );942 //)1016 VISIT( 1017 maybe_accept( node, &ImplicitCtorDtorStmt::callStmt ); 1018 ) 943 1019 944 1020 VISIT_END( Stmt, node ); … … 947 1023 //-------------------------------------------------------------------------- 948 1024 // ApplicationExpr 949 template< typename pass_t >950 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {1025 template< typename core_t > 1026 const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) { 951 1027 VISIT_START( node ); 952 1028 … … 965 1041 //-------------------------------------------------------------------------- 966 1042 // UntypedExpr 967 template< typename pass_t >968 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {1043 template< typename core_t > 1044 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) { 969 1045 VISIT_START( node ); 970 1046 … … 983 1059 //-------------------------------------------------------------------------- 984 1060 // NameExpr 985 template< typename pass_t >986 const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {1061 template< typename core_t > 1062 const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) { 987 1063 VISIT_START( node ); 988 1064 … … 997 1073 //-------------------------------------------------------------------------- 998 1074 // CastExpr 999 template< typename pass_t >1000 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {1075 template< typename core_t > 1076 const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) { 1001 1077 VISIT_START( node ); 1002 1078 … … 1013 1089 //-------------------------------------------------------------------------- 1014 1090 // KeywordCastExpr 1015 template< typename pass_t >1016 const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {1091 template< typename core_t > 1092 const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) { 1017 1093 VISIT_START( node ); 1018 1094 … … 1029 1105 //-------------------------------------------------------------------------- 1030 1106 // VirtualCastExpr 1031 template< typename pass_t >1032 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {1107 template< typename core_t > 1108 const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) { 1033 1109 VISIT_START( node ); 1034 1110 … … 1045 1121 //-------------------------------------------------------------------------- 1046 1122 // AddressExpr 1047 template< typename pass_t >1048 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {1123 template< typename core_t > 1124 const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) { 1049 1125 VISIT_START( node ); 1050 1126 … … 1061 1137 //-------------------------------------------------------------------------- 1062 1138 // LabelAddressExpr 1063 template< typename pass_t >1064 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {1139 template< typename core_t > 1140 const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) { 1065 1141 VISIT_START( node ); 1066 1142 … … 1075 1151 //-------------------------------------------------------------------------- 1076 1152 // UntypedMemberExpr 1077 template< typename pass_t >1078 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {1153 template< typename core_t > 1154 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) { 1079 1155 VISIT_START( node ); 1080 1156 … … 1092 1168 //-------------------------------------------------------------------------- 1093 1169 // MemberExpr 1094 template< typename pass_t >1095 const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {1170 template< typename core_t > 1171 const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) { 1096 1172 VISIT_START( node ); 1097 1173 … … 1108 1184 //-------------------------------------------------------------------------- 1109 1185 // VariableExpr 1110 template< typename pass_t >1111 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {1186 template< typename core_t > 1187 const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) { 1112 1188 VISIT_START( node ); 1113 1189 … … 1122 1198 //-------------------------------------------------------------------------- 1123 1199 // ConstantExpr 1124 template< typename pass_t >1125 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {1200 template< typename core_t > 1201 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) { 1126 1202 VISIT_START( node ); 1127 1203 … … 1136 1212 //-------------------------------------------------------------------------- 1137 1213 // SizeofExpr 1138 template< typename pass_t >1139 const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {1214 template< typename core_t > 1215 const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) { 1140 1216 VISIT_START( node ); 1141 1217 … … 1156 1232 //-------------------------------------------------------------------------- 1157 1233 // AlignofExpr 1158 template< typename pass_t >1159 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {1234 template< typename core_t > 1235 const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) { 1160 1236 VISIT_START( node ); 1161 1237 … … 1176 1252 //-------------------------------------------------------------------------- 1177 1253 // UntypedOffsetofExpr 1178 template< typename pass_t >1179 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {1254 template< typename core_t > 1255 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) { 1180 1256 VISIT_START( node ); 1181 1257 … … 1192 1268 //-------------------------------------------------------------------------- 1193 1269 // OffsetofExpr 1194 template< typename pass_t >1195 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {1270 template< typename core_t > 1271 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) { 1196 1272 VISIT_START( node ); 1197 1273 … … 1208 1284 //-------------------------------------------------------------------------- 1209 1285 // OffsetPackExpr 1210 template< typename pass_t >1211 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {1286 template< typename core_t > 1287 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) { 1212 1288 VISIT_START( node ); 1213 1289 … … 1224 1300 //-------------------------------------------------------------------------- 1225 1301 // LogicalExpr 1226 template< typename pass_t >1227 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {1302 template< typename core_t > 1303 const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) { 1228 1304 VISIT_START( node ); 1229 1305 … … 1241 1317 //-------------------------------------------------------------------------- 1242 1318 // ConditionalExpr 1243 template< typename pass_t >1244 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {1319 template< typename core_t > 1320 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) { 1245 1321 VISIT_START( node ); 1246 1322 … … 1259 1335 //-------------------------------------------------------------------------- 1260 1336 // CommaExpr 1261 template< typename pass_t >1262 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {1337 template< typename core_t > 1338 const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) { 1263 1339 VISIT_START( node ); 1264 1340 … … 1276 1352 //-------------------------------------------------------------------------- 1277 1353 // TypeExpr 1278 template< typename pass_t >1279 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {1354 template< typename core_t > 1355 const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) { 1280 1356 VISIT_START( node ); 1281 1357 … … 1292 1368 //-------------------------------------------------------------------------- 1293 1369 // AsmExpr 1294 template< typename pass_t >1295 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {1370 template< typename core_t > 1371 const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) { 1296 1372 VISIT_START( node ); 1297 1373 … … 1309 1385 //-------------------------------------------------------------------------- 1310 1386 // ImplicitCopyCtorExpr 1311 template< typename pass_t >1312 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {1387 template< typename core_t > 1388 const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) { 1313 1389 VISIT_START( node ); 1314 1390 … … 1325 1401 //-------------------------------------------------------------------------- 1326 1402 // ConstructorExpr 1327 template< typename pass_t >1328 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {1403 template< typename core_t > 1404 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) { 1329 1405 VISIT_START( node ); 1330 1406 … … 1341 1417 //-------------------------------------------------------------------------- 1342 1418 // CompoundLiteralExpr 1343 template< typename pass_t >1344 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {1419 template< typename core_t > 1420 const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) { 1345 1421 VISIT_START( node ); 1346 1422 … … 1357 1433 //-------------------------------------------------------------------------- 1358 1434 // RangeExpr 1359 template< typename pass_t >1360 const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {1435 template< typename core_t > 1436 const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) { 1361 1437 VISIT_START( node ); 1362 1438 … … 1374 1450 //-------------------------------------------------------------------------- 1375 1451 // UntypedTupleExpr 1376 template< typename pass_t >1377 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {1452 template< typename core_t > 1453 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) { 1378 1454 VISIT_START( node ); 1379 1455 … … 1390 1466 //-------------------------------------------------------------------------- 1391 1467 // TupleExpr 1392 template< typename pass_t >1393 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {1468 template< typename core_t > 1469 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) { 1394 1470 VISIT_START( node ); 1395 1471 … … 1406 1482 //-------------------------------------------------------------------------- 1407 1483 // TupleIndexExpr 1408 template< typename pass_t >1409 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {1484 template< typename core_t > 1485 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) { 1410 1486 VISIT_START( node ); 1411 1487 … … 1422 1498 //-------------------------------------------------------------------------- 1423 1499 // TupleAssignExpr 1424 template< typename pass_t >1425 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {1500 template< typename core_t > 1501 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) { 1426 1502 VISIT_START( node ); 1427 1503 … … 1438 1514 //-------------------------------------------------------------------------- 1439 1515 // StmtExpr 1440 template< typename pass_t >1441 const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {1516 template< typename core_t > 1517 const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) { 1442 1518 VISIT_START( node ); 1443 1519 1444 1520 VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr 1445 1521 // get the stmts that will need to be spliced in 1446 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);1447 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);1522 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 1523 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 1448 1524 1449 1525 // These may be modified by subnode but most be restored once we exit this statemnet. 1450 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass:: env( pass, 0) );1526 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::typeSubs( core, 0 ) ); 1451 1527 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 1452 1528 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); … … 1466 1542 //-------------------------------------------------------------------------- 1467 1543 // UniqueExpr 1468 template< typename pass_t >1469 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {1544 template< typename core_t > 1545 const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) { 1470 1546 VISIT_START( node ); 1471 1547 … … 1482 1558 //-------------------------------------------------------------------------- 1483 1559 // UntypedInitExpr 1484 template< typename pass_t >1485 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {1560 template< typename core_t > 1561 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) { 1486 1562 VISIT_START( node ); 1487 1563 … … 1499 1575 //-------------------------------------------------------------------------- 1500 1576 // InitExpr 1501 template< typename pass_t >1502 const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {1577 template< typename core_t > 1578 const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) { 1503 1579 VISIT_START( node ); 1504 1580 … … 1516 1592 //-------------------------------------------------------------------------- 1517 1593 // DeletedExpr 1518 template< typename pass_t >1519 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {1594 template< typename core_t > 1595 const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) { 1520 1596 VISIT_START( node ); 1521 1597 … … 1533 1609 //-------------------------------------------------------------------------- 1534 1610 // DefaultArgExpr 1535 template< typename pass_t >1536 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {1611 template< typename core_t > 1612 const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) { 1537 1613 VISIT_START( node ); 1538 1614 … … 1549 1625 //-------------------------------------------------------------------------- 1550 1626 // GenericExpr 1551 template< typename pass_t >1552 const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {1627 template< typename core_t > 1628 const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) { 1553 1629 VISIT_START( node ); 1554 1630 … … 1578 1654 1579 1655 if(mutated) { 1580 auto n = mutate(node);1656 auto n = __pass::mutate<core_t>(node); 1581 1657 n->associations = std::move( new_kids ); 1582 1658 node = n; … … 1589 1665 //-------------------------------------------------------------------------- 1590 1666 // VoidType 1591 template< typename pass_t >1592 const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {1667 template< typename core_t > 1668 const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) { 1593 1669 VISIT_START( node ); 1594 1670 … … 1598 1674 //-------------------------------------------------------------------------- 1599 1675 // BasicType 1600 template< typename pass_t >1601 const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {1676 template< typename core_t > 1677 const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) { 1602 1678 VISIT_START( node ); 1603 1679 … … 1607 1683 //-------------------------------------------------------------------------- 1608 1684 // PointerType 1609 template< typename pass_t >1610 const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {1685 template< typename core_t > 1686 const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) { 1611 1687 VISIT_START( node ); 1612 1688 … … 1621 1697 //-------------------------------------------------------------------------- 1622 1698 // ArrayType 1623 template< typename pass_t >1624 const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {1699 template< typename core_t > 1700 const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) { 1625 1701 VISIT_START( node ); 1626 1702 … … 1635 1711 //-------------------------------------------------------------------------- 1636 1712 // ReferenceType 1637 template< typename pass_t >1638 const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {1713 template< typename core_t > 1714 const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) { 1639 1715 VISIT_START( node ); 1640 1716 … … 1648 1724 //-------------------------------------------------------------------------- 1649 1725 // QualifiedType 1650 template< typename pass_t >1651 const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {1726 template< typename core_t > 1727 const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) { 1652 1728 VISIT_START( node ); 1653 1729 … … 1662 1738 //-------------------------------------------------------------------------- 1663 1739 // FunctionType 1664 template< typename pass_t > 1665 const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) { 1666 VISIT_START( node ); 1667 1668 VISIT( 1669 maybe_accept( node, &FunctionType::forall ); 1740 template< typename core_t > 1741 const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) { 1742 VISIT_START( node ); 1743 1744 VISIT({ 1745 // guard_forall_subs forall_guard { *this, node }; 1746 // mutate_forall( node ); 1747 maybe_accept( node, &FunctionType::assertions ); 1670 1748 maybe_accept( node, &FunctionType::returns ); 1671 1749 maybe_accept( node, &FunctionType::params ); 1672 )1750 }) 1673 1751 1674 1752 VISIT_END( Type, node ); … … 1677 1755 //-------------------------------------------------------------------------- 1678 1756 // StructInstType 1679 template< typename pass_t >1680 const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {1681 VISIT_START( node ); 1682 1683 __pass::symtab::addStruct( pass, 0, node->name );1757 template< typename core_t > 1758 const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) { 1759 VISIT_START( node ); 1760 1761 __pass::symtab::addStruct( core, 0, node->name ); 1684 1762 1685 1763 VISIT({ 1686 1764 guard_symtab guard { *this }; 1687 maybe_accept( node, &StructInstType::forall );1688 1765 maybe_accept( node, &StructInstType::params ); 1689 1766 }) … … 1694 1771 //-------------------------------------------------------------------------- 1695 1772 // UnionInstType 1696 template< typename pass_t >1697 const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {1698 VISIT_START( node ); 1699 1700 __pass::symtab::add Struct( pass, 0, node->name );1701 1702 {1773 template< typename core_t > 1774 const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) { 1775 VISIT_START( node ); 1776 1777 __pass::symtab::addUnion( core, 0, node->name ); 1778 1779 VISIT({ 1703 1780 guard_symtab guard { *this }; 1704 maybe_accept( node, &UnionInstType::forall );1705 1781 maybe_accept( node, &UnionInstType::params ); 1706 } 1782 }) 1707 1783 1708 1784 VISIT_END( Type, node ); … … 1711 1787 //-------------------------------------------------------------------------- 1712 1788 // EnumInstType 1713 template< typename pass_t > 1714 const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) { 1715 VISIT_START( node ); 1716 1717 VISIT( 1718 maybe_accept( node, &EnumInstType::forall ); 1789 template< typename core_t > 1790 const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) { 1791 VISIT_START( node ); 1792 1793 VISIT({ 1719 1794 maybe_accept( node, &EnumInstType::params ); 1720 )1795 }) 1721 1796 1722 1797 VISIT_END( Type, node ); … … 1725 1800 //-------------------------------------------------------------------------- 1726 1801 // TraitInstType 1727 template< typename pass_t > 1728 const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) { 1729 VISIT_START( node ); 1730 1731 VISIT( 1732 maybe_accept( node, &TraitInstType::forall ); 1802 template< typename core_t > 1803 const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) { 1804 VISIT_START( node ); 1805 1806 VISIT({ 1733 1807 maybe_accept( node, &TraitInstType::params ); 1734 )1808 }) 1735 1809 1736 1810 VISIT_END( Type, node ); … … 1739 1813 //-------------------------------------------------------------------------- 1740 1814 // TypeInstType 1741 template< typename pass_t > 1742 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) { 1743 VISIT_START( node ); 1744 1745 VISIT( 1746 maybe_accept( node, &TypeInstType::forall ); 1747 maybe_accept( node, &TypeInstType::params ); 1815 template< typename core_t > 1816 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) { 1817 VISIT_START( node ); 1818 1819 VISIT( 1820 { 1821 maybe_accept( node, &TypeInstType::params ); 1822 } 1823 // ensure that base re-bound if doing substitution 1824 __pass::forall::replace( core, 0, node ); 1748 1825 ) 1749 1826 … … 1753 1830 //-------------------------------------------------------------------------- 1754 1831 // TupleType 1755 template< typename pass_t >1756 const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {1832 template< typename core_t > 1833 const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) { 1757 1834 VISIT_START( node ); 1758 1835 … … 1767 1844 //-------------------------------------------------------------------------- 1768 1845 // TypeofType 1769 template< typename pass_t >1770 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {1846 template< typename core_t > 1847 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) { 1771 1848 VISIT_START( node ); 1772 1849 … … 1780 1857 //-------------------------------------------------------------------------- 1781 1858 // VarArgsType 1782 template< typename pass_t >1783 const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {1859 template< typename core_t > 1860 const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) { 1784 1861 VISIT_START( node ); 1785 1862 … … 1789 1866 //-------------------------------------------------------------------------- 1790 1867 // ZeroType 1791 template< typename pass_t >1792 const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {1868 template< typename core_t > 1869 const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) { 1793 1870 VISIT_START( node ); 1794 1871 … … 1798 1875 //-------------------------------------------------------------------------- 1799 1876 // OneType 1800 template< typename pass_t >1801 const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {1877 template< typename core_t > 1878 const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) { 1802 1879 VISIT_START( node ); 1803 1880 … … 1807 1884 //-------------------------------------------------------------------------- 1808 1885 // GlobalScopeType 1809 template< typename pass_t >1810 const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {1886 template< typename core_t > 1887 const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) { 1811 1888 VISIT_START( node ); 1812 1889 … … 1817 1894 //-------------------------------------------------------------------------- 1818 1895 // Designation 1819 template< typename pass_t >1820 const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {1896 template< typename core_t > 1897 const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) { 1821 1898 VISIT_START( node ); 1822 1899 … … 1828 1905 //-------------------------------------------------------------------------- 1829 1906 // SingleInit 1830 template< typename pass_t >1831 const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {1907 template< typename core_t > 1908 const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) { 1832 1909 VISIT_START( node ); 1833 1910 … … 1841 1918 //-------------------------------------------------------------------------- 1842 1919 // ListInit 1843 template< typename pass_t >1844 const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {1920 template< typename core_t > 1921 const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) { 1845 1922 VISIT_START( node ); 1846 1923 … … 1855 1932 //-------------------------------------------------------------------------- 1856 1933 // ConstructorInit 1857 template< typename pass_t >1858 const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {1934 template< typename core_t > 1935 const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) { 1859 1936 VISIT_START( node ); 1860 1937 … … 1870 1947 //-------------------------------------------------------------------------- 1871 1948 // Attribute 1872 template< typename pass_t >1873 const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node ) {1949 template< typename core_t > 1950 const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node ) { 1874 1951 VISIT_START( node ); 1875 1952 … … 1883 1960 //-------------------------------------------------------------------------- 1884 1961 // TypeSubstitution 1885 template< typename pass_t >1886 const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {1962 template< typename core_t > 1963 const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) { 1887 1964 VISIT_START( node ); 1888 1965 … … 1890 1967 { 1891 1968 bool mutated = false; 1892 std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;1969 std::unordered_map< ast::TypeInstType::TypeEnvKey, ast::ptr< ast::Type > > new_map; 1893 1970 for ( const auto & p : node->typeEnv ) { 1894 1971 guard_symtab guard { *this }; 1895 1972 auto new_node = p.second->accept( *this ); 1896 if (new_node != p.second) mutated = false;1973 if (new_node != p.second) mutated = true; 1897 1974 new_map.insert({ p.first, new_node }); 1898 1975 } 1899 1976 if (mutated) { 1900 auto new_node = mutate( node );1977 auto new_node = __pass::mutate<core_t>( node ); 1901 1978 new_node->typeEnv.swap( new_map ); 1902 1979 node = new_node; 1903 1980 } 1904 1981 } 1905 1906 {1907 bool mutated = false;1908 std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;1909 for ( const auto & p : node->varEnv ) {1910 guard_symtab guard { *this };1911 auto new_node = p.second->accept( *this );1912 if (new_node != p.second) mutated = false;1913 new_map.insert({ p.first, new_node });1914 }1915 if (mutated) {1916 auto new_node = mutate( node );1917 new_node->varEnv.swap( new_map );1918 node = new_node;1919 }1920 }1921 1982 ) 1922 1983 -
src/AST/Pass.proto.hpp
rbdfc032 reef8dfb 17 17 // IWYU pragma: private, include "Pass.hpp" 18 18 19 #include "Common/Stats/Heap.h" 20 19 21 namespace ast { 20 template<typename pass_type>22 template<typename core_t> 21 23 class Pass; 24 25 struct TranslationUnit; 26 27 struct PureVisitor; 22 28 23 29 namespace __pass { … … 82 88 }; 83 89 84 std::stack< cleanup_t > cleanups;90 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 85 91 }; 86 92 … … 111 117 /// "Short hand" to check if this is a valid previsit function 112 118 /// Mostly used to make the static_assert look (and print) prettier 113 template<typename pass_t, typename node_t>119 template<typename core_t, typename node_t> 114 120 struct is_valid_previsit { 115 using ret_t = decltype( (( pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );121 using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) ); 116 122 117 123 static constexpr bool value = std::is_void< ret_t >::value || … … 127 133 template<> 128 134 struct __assign<true> { 129 template<typename pass_t, typename node_t>130 static inline void result( pass_t & pass, const node_t * & node ) {131 pass.previsit( node );135 template<typename core_t, typename node_t> 136 static inline void result( core_t & core, const node_t * & node ) { 137 core.previsit( node ); 132 138 } 133 139 }; … … 135 141 template<> 136 142 struct __assign<false> { 137 template<typename pass_t, typename node_t>138 static inline void result( pass_t & pass, const node_t * & node ) {139 node = pass.previsit( node );143 template<typename core_t, typename node_t> 144 static inline void result( core_t & core, const node_t * & node ) { 145 node = core.previsit( node ); 140 146 assertf(node, "Previsit must not return NULL"); 141 147 } … … 150 156 template<> 151 157 struct __return<true> { 152 template<typename pass_t, typename node_t>153 static inline const node_t * result( pass_t & pass, const node_t * & node ) {154 pass.postvisit( node );158 template<typename core_t, typename node_t> 159 static inline const node_t * result( core_t & core, const node_t * & node ) { 160 core.postvisit( node ); 155 161 return node; 156 162 } … … 159 165 template<> 160 166 struct __return<false> { 161 template<typename pass_t, typename node_t>162 static inline auto result( pass_t & pass, const node_t * & node ) {163 return pass.postvisit( node );167 template<typename core_t, typename node_t> 168 static inline auto result( core_t & core, const node_t * & node ) { 169 return core.postvisit( node ); 164 170 } 165 171 }; … … 180 186 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 181 187 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 182 template<typename pass_t, typename node_t>183 static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {188 template<typename core_t, typename node_t> 189 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 184 190 static_assert( 185 is_valid_previsit< pass_t, node_t>::value,191 is_valid_previsit<core_t, node_t>::value, 186 192 "Previsit may not change the type of the node. It must return its paremeter or void." 187 193 ); … … 189 195 __assign< 190 196 std::is_void< 191 decltype( pass.previsit( node ) )197 decltype( core.previsit( node ) ) 192 198 >::value 193 >::result( pass, node );194 } 195 196 template<typename pass_t, typename node_t>197 static inline auto previsit( pass_t &, const node_t *, long ) {}199 >::result( core, node ); 200 } 201 202 template<typename core_t, typename node_t> 203 static inline auto previsit( core_t &, const node_t *, long ) {} 198 204 199 205 // PostVisit : never mutates the passed pointer but may return a different node 200 template<typename pass_t, typename node_t>201 static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->202 decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )206 template<typename core_t, typename node_t> 207 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 208 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 203 209 { 204 210 return __return< 205 211 std::is_void< 206 decltype( pass.postvisit( node ) )212 decltype( core.postvisit( node ) ) 207 213 >::value 208 >::result( pass, node );209 } 210 211 template<typename pass_t, typename node_t>212 static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }214 >::result( core, node ); 215 } 216 217 template<typename core_t, typename node_t> 218 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 213 219 214 220 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- … … 225 231 // The type is not strictly enforced but does match the accessory 226 232 #define FIELD_PTR( name, default_type ) \ 227 template< typename pass_t > \228 static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \233 template< typename core_t > \ 234 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 229 235 \ 230 template< typename pass_t > \231 static inline default_type * name( pass_t &, long ) { return nullptr; }236 template< typename core_t > \ 237 static inline default_type * name( core_t &, long ) { return nullptr; } 232 238 233 239 // List of fields and their expected types 234 FIELD_PTR( env, const ast::TypeSubstitution * )240 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 235 241 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 236 242 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) … … 239 245 FIELD_PTR( visit_children, __pass::bool_ref ) 240 246 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 241 FIELD_PTR( visitor, ast::Pass< pass_t> * const )247 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 242 248 243 249 // Remove the macro to make sure we don't clash 244 250 #undef FIELD_PTR 251 252 template< typename core_t > 253 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 254 // Stats::Heap::stacktrace_push(core_t::traceId); 255 } 256 257 template< typename core_t > 258 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 259 // Stats::Heap::stacktrace_pop(); 260 } 261 262 template< typename core_t > 263 static void beginTrace(core_t &, long) {} 264 265 template< typename core_t > 266 static void endTrace(core_t &, long) {} 267 268 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 269 // If onError() returns false, the error will be ignored. By default, it returns true. 270 271 template< typename core_t > 272 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 273 274 template< typename core_t > 275 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 276 return core.on_error(decl); 277 } 245 278 246 279 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. … … 248 281 // detect it using the same strategy 249 282 namespace scope { 250 template<typename pass_t>251 static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {252 pass.beginScope();253 } 254 255 template<typename pass_t>256 static inline void enter( pass_t &, long ) {}257 258 template<typename pass_t>259 static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {260 pass.endScope();261 } 262 263 template<typename pass_t>264 static inline void leave( pass_t &, long ) {}265 } ;266 267 // Finally certain pass desire an up to date symbol table automatically283 template<typename core_t> 284 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 285 core.beginScope(); 286 } 287 288 template<typename core_t> 289 static inline void enter( core_t &, long ) {} 290 291 template<typename core_t> 292 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 293 core.endScope(); 294 } 295 296 template<typename core_t> 297 static inline void leave( core_t &, long ) {} 298 } // namespace scope 299 300 // Certain passes desire an up to date symbol table automatically 268 301 // detect the presence of a member name `symtab` and call all the members appropriately 269 302 namespace symtab { 270 303 // Some simple scoping rules 271 template<typename pass_t>272 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {273 pass.symtab.enterScope();274 } 275 276 template<typename pass_t>277 static inline auto enter( pass_t &, long ) {}278 279 template<typename pass_t>280 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {281 pass.symtab.leaveScope();282 } 283 284 template<typename pass_t>285 static inline auto leave( pass_t &, long ) {}304 template<typename core_t> 305 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 306 core.symtab.enterScope(); 307 } 308 309 template<typename core_t> 310 static inline auto enter( core_t &, long ) {} 311 312 template<typename core_t> 313 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 314 core.symtab.leaveScope(); 315 } 316 317 template<typename core_t> 318 static inline auto leave( core_t &, long ) {} 286 319 287 320 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 288 321 // Create macro to condense these common patterns 289 322 #define SYMTAB_FUNC1( func, type ) \ 290 template<typename pass_t> \291 static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.symtab.func( arg ), void() ) {\292 pass.symtab.func( arg ); \323 template<typename core_t> \ 324 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 325 core.symtab.func( arg ); \ 293 326 } \ 294 327 \ 295 template<typename pass_t> \296 static inline void func( pass_t &, long, type ) {}328 template<typename core_t> \ 329 static inline void func( core_t &, long, type ) {} 297 330 298 331 #define SYMTAB_FUNC2( func, type1, type2 ) \ 299 template<typename pass_t> \300 static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.symtab.func( arg1, arg2 ), void () ) {\301 pass.symtab.func( arg1, arg2 ); \332 template<typename core_t> \ 333 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 334 core.symtab.func( arg1, arg2 ); \ 302 335 } \ 303 336 \ 304 template<typename pass_t> \305 static inline void func( pass_t &, long, type1, type2 ) {}337 template<typename core_t> \ 338 static inline void func( core_t &, long, type1, type2 ) {} 306 339 307 340 SYMTAB_FUNC1( addId , const DeclWithType * ); … … 311 344 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 312 345 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 313 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Node* );346 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 314 347 315 348 // A few extra functions have more complicated behaviour, they are hand written 316 template<typename pass_t>317 static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {349 template<typename core_t> 350 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 318 351 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 319 352 fwd->params = decl->params; 320 pass.symtab.addStruct( fwd );321 } 322 323 template<typename pass_t>324 static inline void addStructFwd( pass_t &, long, const ast::StructDecl * ) {}325 326 template<typename pass_t>327 static inline auto addUnionFwd( pass_t & pass, int, const ast::UnionDecl * decl ) -> decltype( pass.symtab.addUnion( decl ), void() ) {353 core.symtab.addStruct( fwd ); 354 } 355 356 template<typename core_t> 357 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 358 359 template<typename core_t> 360 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 328 361 UnionDecl * fwd = new UnionDecl( decl->location, decl->name ); 329 362 fwd->params = decl->params; 330 pass.symtab.addUnion( fwd );331 } 332 333 template<typename pass_t>334 static inline void addUnionFwd( pass_t &, long, const ast::UnionDecl * ) {}335 336 template<typename pass_t>337 static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addStruct( str ), void() ) {338 if ( ! pass.symtab.lookupStruct( str ) ) {339 pass.symtab.addStruct( str );363 core.symtab.addUnion( fwd ); 364 } 365 366 template<typename core_t> 367 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 368 369 template<typename core_t> 370 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 371 if ( ! core.symtab.lookupStruct( str ) ) { 372 core.symtab.addStruct( str ); 340 373 } 341 374 } 342 375 343 template<typename pass_t>344 static inline void addStruct( pass_t &, long, const std::string & ) {}345 346 template<typename pass_t>347 static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addUnion( str ), void() ) {348 if ( ! pass.symtab.lookupUnion( str ) ) {349 pass.symtab.addUnion( str );376 template<typename core_t> 377 static inline void addStruct( core_t &, long, const std::string & ) {} 378 379 template<typename core_t> 380 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 381 if ( ! core.symtab.lookupUnion( str ) ) { 382 core.symtab.addUnion( str ); 350 383 } 351 384 } 352 385 353 template<typename pass_t>354 static inline void addUnion( pass_t &, long, const std::string & ) {}386 template<typename core_t> 387 static inline void addUnion( core_t &, long, const std::string & ) {} 355 388 356 389 #undef SYMTAB_FUNC1 357 390 #undef SYMTAB_FUNC2 358 }; 359 }; 360 }; 391 } // namespace symtab 392 393 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 394 // Detect the presence of a member name `subs` and call all members appropriately 395 namespace forall { 396 // Some simple scoping rules 397 template<typename core_t> 398 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 399 -> decltype( core.subs, void() ) { 400 if ( ! type->forall.empty() ) core.subs.beginScope(); 401 } 402 403 template<typename core_t> 404 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 405 406 template<typename core_t> 407 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 408 -> decltype( core.subs, void() ) { 409 if ( ! type->forall.empty() ) { core.subs.endScope(); } 410 } 411 412 template<typename core_t> 413 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 414 415 // Replaces a TypeInstType's base TypeDecl according to the table 416 template<typename core_t> 417 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 418 -> decltype( core.subs, void() ) { 419 inst = ast::mutate_field( 420 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 421 } 422 423 template<typename core_t> 424 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 425 426 } // namespace forall 427 428 template<typename core_t> 429 static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) { 430 return core.result(); 431 } 432 433 template<typename core_t> 434 static inline auto get_result( core_t & core, int ) -> decltype( core.result ) { 435 return core.result; 436 } 437 438 template<typename core_t> 439 static inline void get_result( core_t &, long ) {} 440 } // namespace __pass 441 } // namespace ast -
src/AST/Print.cpp
rbdfc032 reef8dfb 21 21 #include "Type.hpp" 22 22 #include "TypeSubstitution.hpp" 23 #include "CompilationState.h" 23 24 24 25 #include "Common/utility.h" // for group_iterate … … 29 30 30 31 template <typename C, typename... T> 31 constexpr auto make_array(T&&... values) -> 32 array<C,sizeof...(T)> 32 constexpr array<C,sizeof...(T)> make_array(T&&... values) 33 33 { 34 34 return array<C,sizeof...(T)>{ … … 129 129 130 130 void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) { 131 switch ( inferred.mode ) { 132 case ast::Expr::InferUnion::Empty: return; 133 case ast::Expr::InferUnion::Slots: { 134 os << indent << "with " << inferred.data.resnSlots.size() 131 if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) { 132 os << indent << "with " << inferred.data.resnSlots->size() 135 133 << " pending inference slots" << endl; 136 return; 137 } 138 case ast::Expr::InferUnion::Params: { 134 } 135 if (inferred.data.inferParams && !inferred.data.inferParams->empty()) { 139 136 os << indent << "with inferred parameters " << level << ":" << endl; 140 137 ++indent; 141 for ( const auto & i : inferred.data.inferParams ) {138 for ( const auto & i : *inferred.data.inferParams ) { 142 139 os << indent; 143 short_print( Decl::fromId( i.second.decl ));140 short_print( i.second.declptr ); 144 141 os << endl; 145 142 print( i.second.expr->inferred, level+1 ); 146 143 } 147 144 --indent; 148 return; 149 } 150 } 151 } 152 153 void print( const ast::ParameterizedType::ForallList & forall ) { 145 } 146 } 147 148 void print( const ast::FunctionType::ForallList & forall ) { 154 149 if ( forall.empty() ) return; 155 150 os << "forall" << endl; 156 151 ++indent; 157 152 printAll( forall ); 153 os << indent; 154 --indent; 155 } 156 157 void print( const ast::FunctionType::AssertionList & assts ) { 158 if (assts.empty()) return; 159 os << "with assertions" << endl; 160 ++indent; 161 printAll(assts); 158 162 os << indent; 159 163 --indent; … … 210 214 211 215 void preprint( const ast::NamedTypeDecl * node ) { 212 if ( ! node->name.empty() ) os << node->name << ": "; 216 if ( ! node->name.empty() ) { 217 os << node->name << ": "; 218 } 213 219 214 220 if ( ! short_mode && node->linkage != Linkage::Cforall ) { … … 226 232 } 227 233 228 if ( ! node->params.empty() ) { 229 os << endl << indent << "... with parameters" << endl; 230 ++indent; 231 printAll( node->params ); 232 --indent; 233 } 234 235 if ( ! short_mode && ! node->assertions.empty() ) { 234 if ( ! node->assertions.empty() ) { 236 235 os << endl << indent << "... with assertions" << endl; 237 236 ++indent; … … 244 243 print( node->inferred ); 245 244 245 if ( node->result ) { 246 os << endl << indent << "... with resolved type:" << endl; 247 ++indent; 248 os << indent; 249 node->result->accept( *this ); 250 --indent; 251 } 252 246 253 if ( node->env ) { 247 254 os << endl << indent << "... with environment:" << endl; … … 260 267 } 261 268 262 void preprint( const ast:: ParameterizedType * node ) {269 void preprint( const ast::FunctionType * node ) { 263 270 print( node->forall ); 271 print( node->assertions ); 264 272 print( node->qualifiers ); 265 273 } 266 274 267 void preprint( const ast::ReferenceToType * node ) { 268 print( node->forall ); 275 void preprint( const ast::BaseInstType * node ) { 269 276 print( node->attributes ); 270 277 print( node->qualifiers ); … … 678 685 } 679 686 687 virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final { 688 os << "Suspend Statement"; 689 switch (node->type) { 690 case ast::SuspendStmt::None : os << " with implicit target"; break; 691 case ast::SuspendStmt::Generator: os << " for generator"; break; 692 case ast::SuspendStmt::Coroutine: os << " for coroutine"; break; 693 } 694 os << endl; 695 696 ++indent; 697 if(node->then) { 698 os << indent << " with post statement :" << endl; 699 safe_print( node->then ); 700 } 701 ++indent; 702 703 return node; 704 } 705 680 706 virtual const ast::Stmt * visit( const ast::WaitForStmt * node ) override final { 681 707 os << "Waitfor Statement" << endl; … … 823 849 virtual const ast::Expr * visit( const ast::CastExpr * node ) override final { 824 850 ++indent; 825 os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;851 os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent; 826 852 safe_print( node->arg ); 827 853 os << endl << indent-1 << "... to:"; … … 1358 1384 virtual const ast::Type * visit( const ast::TypeInstType * node ) override final { 1359 1385 preprint( node ); 1360 os << "instance of type " << node->name 1386 const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->typeString(); 1387 os << "instance of type " << _name 1361 1388 << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)"; 1362 1389 print( node->params ); … … 1484 1511 os << indent << "Types:" << endl; 1485 1512 for ( const auto& i : *node ) { 1486 os << indent+1 << i.first << " -> ";1513 os << indent+1 << i.first.typeString() << " -> "; 1487 1514 indent += 2; 1488 1515 safe_print( i.second ); 1489 indent -= 2;1490 os << endl;1491 }1492 os << indent << "Non-types:" << endl;1493 for ( auto i = node->beginVar(); i != node->endVar(); ++i ) {1494 os << indent+1 << i->first << " -> ";1495 indent += 2;1496 safe_print( i->second );1497 1516 indent -= 2; 1498 1517 os << endl; -
src/AST/Stmt.hpp
rbdfc032 reef8dfb 27 27 28 28 // Must be included in *all* AST classes; should be #undef'd at the end of the file 29 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 29 #define MUTATE_FRIEND \ 30 template<typename node_t> friend node_t * mutate(const node_t * node); \ 31 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 30 32 31 33 namespace ast { … … 342 344 }; 343 345 346 /// Suspend statement 347 class SuspendStmt final : public Stmt { 348 public: 349 ptr<CompoundStmt> then; 350 enum Type { None, Coroutine, Generator } type = None; 351 352 SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, std::vector<Label> && labels = {} ) 353 : Stmt(loc, std::move(labels)), then(then), type(type) {} 354 355 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 356 private: 357 SuspendStmt * clone() const override { return new SuspendStmt{ *this }; } 358 MUTATE_FRIEND 359 }; 360 344 361 /// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...` 345 362 class WaitForStmt final : public Stmt { … … 397 414 class ImplicitCtorDtorStmt final : public Stmt { 398 415 public: 399 readonly<Stmt> callStmt;416 ptr<Stmt> callStmt; 400 417 401 418 ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt, -
src/AST/SymbolTable.cpp
rbdfc032 reef8dfb 95 95 } 96 96 97 SymbolTable::SpecialFunctionKind SymbolTable::getSpecialFunctionKind(const std::string & name) { 98 if (name == "?{}") return CTOR; 99 if (name == "^?{}") return DTOR; 100 if (name == "?=?") return ASSIGN; 101 return NUMBER_OF_KINDS; 102 } 103 97 104 std::vector<SymbolTable::IdData> SymbolTable::lookupId( const std::string &id ) const { 105 static Stats::Counters::CounterGroup * name_lookup_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Name Lookup Stats"); 106 static std::map<std::string, Stats::Counters::SimpleCounter *> lookups_by_name; 107 static std::map<std::string, Stats::Counters::SimpleCounter *> candidates_by_name; 108 109 SpecialFunctionKind kind = getSpecialFunctionKind(id); 110 if (kind != NUMBER_OF_KINDS) return specialLookupId(kind); 111 98 112 ++*stats().lookup_calls; 99 113 if ( ! idTable ) return {}; … … 107 121 out.push_back( decl.second ); 108 122 } 123 124 if (Stats::Counters::enabled) { 125 if (! lookups_by_name.count(id)) { 126 // leaks some strings, but it is because Counters do not hold them 127 auto lookupCounterName = new std::string(id + "%count"); 128 auto candidatesCounterName = new std::string(id + "%candidate"); 129 lookups_by_name.emplace(id, new Stats::Counters::SimpleCounter(lookupCounterName->c_str(), name_lookup_stats)); 130 candidates_by_name.emplace(id, new Stats::Counters::SimpleCounter(candidatesCounterName->c_str(), name_lookup_stats)); 131 } 132 (*lookups_by_name[id]) ++; 133 *candidates_by_name[id] += out.size(); 134 } 135 136 return out; 137 } 138 139 std::vector<SymbolTable::IdData> SymbolTable::specialLookupId( SymbolTable::SpecialFunctionKind kind, const std::string & otypeKey ) const { 140 static Stats::Counters::CounterGroup * special_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Special Lookups"); 141 static Stats::Counters::SimpleCounter * stat_counts[3] = { 142 Stats::Counters::build<Stats::Counters::SimpleCounter>("constructor - count", special_stats), 143 Stats::Counters::build<Stats::Counters::SimpleCounter>("destructor - count", special_stats), 144 Stats::Counters::build<Stats::Counters::SimpleCounter>("assignment - count", special_stats) 145 }; 146 147 static Stats::Counters::SimpleCounter * stat_candidates[3] = { 148 Stats::Counters::build<Stats::Counters::SimpleCounter>("constructor - candidates", special_stats), 149 Stats::Counters::build<Stats::Counters::SimpleCounter>("destructor - candidates", special_stats), 150 Stats::Counters::build<Stats::Counters::SimpleCounter>("assignment - candidates", special_stats) 151 }; 152 153 static Stats::Counters::SimpleCounter * num_lookup_with_key 154 = Stats::Counters::build<Stats::Counters::SimpleCounter>("keyed lookups", special_stats); 155 static Stats::Counters::SimpleCounter * num_lookup_without_key 156 = Stats::Counters::build<Stats::Counters::SimpleCounter>("unkeyed lookups", special_stats); 157 158 assert (kind != NUMBER_OF_KINDS); 159 ++*stats().lookup_calls; 160 if ( ! specialFunctionTable[kind] ) return {}; 161 162 std::vector<IdData> out; 163 164 if (otypeKey.empty()) { // returns everything 165 ++*num_lookup_without_key; 166 for (auto & table : *specialFunctionTable[kind]) { 167 for (auto & decl : *table.second) { 168 out.push_back(decl.second); 169 } 170 } 171 } 172 else { 173 ++*num_lookup_with_key; 174 ++*stats().map_lookups; 175 auto decls = specialFunctionTable[kind]->find(otypeKey); 176 if (decls == specialFunctionTable[kind]->end()) return {}; 177 178 for (auto decl : *(decls->second)) { 179 out.push_back(decl.second); 180 } 181 } 182 183 ++*stat_counts[kind]; 184 *stat_candidates[kind] += out.size(); 185 109 186 return out; 110 187 } … … 313 390 if ( ! expr->result ) continue; 314 391 const Type * resTy = expr->result->stripReferences(); 315 auto aggrType = dynamic_cast< const ReferenceToType * >( resTy );392 auto aggrType = dynamic_cast< const BaseInstType * >( resTy ); 316 393 assertf( aggrType, "WithStmt expr has non-aggregate type: %s", 317 394 toString( expr->result ).c_str() ); … … 335 412 } 336 413 337 void SymbolTable::addFunctionType( const FunctionType * ftype ) { 338 addTypes( ftype->forall ); 339 addIds( ftype->returns ); 340 addIds( ftype->params ); 341 } 414 415 void SymbolTable::addFunction( const FunctionDecl * func ) { 416 for (auto & td : func->type_params) { 417 addType(td); 418 } 419 for (auto & asst : func->assertions) { 420 addId(asst); 421 } 422 // addTypes( func->type->forall ); 423 addIds( func->returns ); 424 addIds( func->params ); 425 } 426 342 427 343 428 void SymbolTable::lazyInitScope() { … … 364 449 namespace { 365 450 /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function 366 std::string getOtypeKey( const Function Decl * function) {367 const auto & params = f unction->type->params;451 std::string getOtypeKey( const FunctionType * ftype, bool stripParams = true ) { 452 const auto & params = ftype->params; 368 453 assert( ! params.empty() ); 369 454 // use base type of pointer, so that qualifiers on the pointer type aren't considered. 370 const Type * base = InitTweak::getPointerBase( params.front() ->get_type());455 const Type * base = InitTweak::getPointerBase( params.front() ); 371 456 assert( base ); 372 return Mangle::mangle( base ); 457 if (stripParams) { 458 if (dynamic_cast<const PointerType *>(base)) return Mangle::Encoding::pointer; 459 return Mangle::mangle( base, Mangle::Type | Mangle::NoGenericParams ); 460 } 461 else 462 return Mangle::mangle( base ); 373 463 } 374 464 … … 378 468 const DeclWithType * decl, const std::string & otypeKey ) { 379 469 auto func = dynamic_cast< const FunctionDecl * >( decl ); 380 if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;470 if ( ! func || otypeKey != getOtypeKey( func->type, false ) ) return nullptr; 381 471 return func; 382 472 } … … 403 493 bool dataIsUserDefinedFunc = ! function->linkage.is_overrideable; 404 494 bool dataIsCopyFunc = InitTweak::isCopyFunction( function ); 405 std::string dataOtypeKey = getOtypeKey( function );495 std::string dataOtypeKey = getOtypeKey( function->type, false ); // requires exact match to override autogen 406 496 407 497 if ( dataIsUserDefinedFunc && dataIsCopyFunc ) { … … 575 665 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr, 576 666 const Decl * deleter ) { 667 SpecialFunctionKind kind = getSpecialFunctionKind(decl->name); 668 if (kind == NUMBER_OF_KINDS) { // not a special decl 669 addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter); 670 } 671 else { 672 std::string key; 673 if (auto func = dynamic_cast<const FunctionDecl *>(decl)) { 674 key = getOtypeKey(func->type); 675 } 676 else if (auto obj = dynamic_cast<const ObjectDecl *>(decl)) { 677 key = getOtypeKey(obj->type.strict_as<PointerType>()->base.strict_as<FunctionType>()); 678 } 679 else { 680 assertf(false, "special decl with non-function type"); 681 } 682 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter); 683 } 684 } 685 686 void SymbolTable::addId( 687 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr, 688 const Decl * deleter ) { 577 689 ++*stats().add_calls; 578 690 const std::string &name = decl->name; … … 605 717 // ensure tables exist and add identifier 606 718 MangleTable::Ptr mangleTable; 607 if ( ! idTable ) {608 idTable = IdTable::new_ptr();719 if ( ! table ) { 720 table = IdTable::new_ptr(); 609 721 mangleTable = MangleTable::new_ptr(); 610 722 } else { 611 723 ++*stats().map_lookups; 612 auto decls = idTable->find( name);613 if ( decls == idTable->end() ) {724 auto decls = table->find( lookupKey ); 725 if ( decls == table->end() ) { 614 726 mangleTable = MangleTable::new_ptr(); 615 727 } else { … … 626 738 lazyInitScope(); 627 739 *stats().map_mutations += 2; 628 idTable = idTable->set(629 name,740 table = table->set( 741 lookupKey, 630 742 mangleTable->set( 631 743 mangleName, … … 642 754 IdData data{ decl, baseExpr, deleter, scope }; 643 755 // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary 644 if ( ! removeSpecialOverrides( data, mangleTable ) ) return; 756 if (table != idTable) { // adding to special table 757 if ( ! removeSpecialOverrides( data, mangleTable ) ) return; 758 } 645 759 *stats().map_mutations += 2; 646 idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );760 table = table->set( lookupKey, mangleTable->set( mangleName, std::move(data) ) ); 647 761 } 648 762 … … 654 768 if ( dwt->name == "" ) { 655 769 const Type * t = dwt->get_type()->stripReferences(); 656 if ( auto rty = dynamic_cast<const ReferenceToType *>( t ) ) {770 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) { 657 771 if ( ! dynamic_cast<const StructInstType *>(rty) 658 772 && ! dynamic_cast<const UnionInstType *>(rty) ) continue; -
src/AST/SymbolTable.hpp
rbdfc032 reef8dfb 33 33 class SymbolTable final : public std::enable_shared_from_this<ast::SymbolTable> { 34 34 public: 35 /// special functions stored in dedicated tables, with different lookup keys 36 enum SpecialFunctionKind {CTOR, DTOR, ASSIGN, NUMBER_OF_KINDS}; 37 static SpecialFunctionKind getSpecialFunctionKind(const std::string & name); 38 35 39 /// Stored information about a declaration 36 40 struct IdData { … … 77 81 UnionTable::Ptr unionTable; ///< union namespace 78 82 TraitTable::Ptr traitTable; ///< trait namespace 83 IdTable::Ptr specialFunctionTable[NUMBER_OF_KINDS]; 84 85 // using SpecialFuncTable = PersistentMap< std::string, IdTable::Ptr >; // fname (ctor/dtor/assign) - otypekey 86 // SpecialFuncTable::Ptr specialFuncTable; 79 87 80 88 using Ptr = std::shared_ptr<const SymbolTable>; … … 95 103 /// Gets all declarations with the given ID 96 104 std::vector<IdData> lookupId( const std::string &id ) const; 105 /// Gets special functions associated with a type; if no key is given, returns everything 106 std::vector<IdData> specialLookupId( SpecialFunctionKind kind, const std::string & otypeKey = "" ) const; 97 107 /// Gets the top-most type declaration with the given ID 98 108 const NamedTypeDecl * lookupType( const std::string &id ) const; … … 145 155 146 156 /// convenience function for adding all of the declarations in a function type to the indexer 147 void addFunction Type( const FunctionType * ftype);157 void addFunction( const FunctionDecl * ); 148 158 149 159 private: … … 186 196 const Decl * deleter = nullptr ); 187 197 198 /// common code for addId when special decls are placed into separate tables 199 void addId( 200 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & idTable, OnConflict handleConflicts, 201 const Expr * baseExpr = nullptr, const Decl * deleter = nullptr); 202 188 203 /// adds all of the members of the Aggregate (addWith helper) 189 204 void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts ); -
src/AST/Type.cpp
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Mon May 13 15:00:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun Dec 15 16:56:28 201913 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Jul 23 14:16:00 2020 13 // Update Count : 5 14 14 // 15 15 … … 22 22 #include "Decl.hpp" 23 23 #include "Init.hpp" 24 #include "Common/utility.h" // for copy, move 24 25 #include "InitTweak/InitTweak.h" // for getPointerBase 25 26 #include "Tuples/Tuples.h" // for isTtype … … 91 92 92 93 // --- FunctionType 93 94 94 namespace { 95 bool containsTtype( const std::vector<ptr< DeclWithType>> & l ) {95 bool containsTtype( const std::vector<ptr<Type>> & l ) { 96 96 if ( ! l.empty() ) { 97 return Tuples::isTtype( l.back() ->get_type());97 return Tuples::isTtype( l.back() ); 98 98 } 99 99 return false; … … 105 105 } 106 106 107 // --- ReferenceToType 108 std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const { 107 std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const { 109 108 assertf( aggr(), "Must have aggregate to perform lookup" ); 110 109 … … 116 115 } 117 116 118 // --- S tructInstType117 // --- SueInstType (StructInstType, UnionInstType, EnumInstType) 119 118 120 StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q, 121 std::vector<ptr<Attribute>>&& as ) 122 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {} 119 template<typename decl_t> 120 SueInstType<decl_t>::SueInstType( 121 const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 122 : BaseInstType( b->name, q, move(as) ), base( b ) {} 123 123 124 bool StructInstType::isComplete() const { return base ? base->body : false; } 124 template<typename decl_t> 125 SueInstType<decl_t>::SueInstType( 126 const base_type * b, std::vector<ptr<Expr>> && params, 127 CV::Qualifiers q, std::vector<ptr<Attribute>> && as ) 128 : BaseInstType( b->name, std::move(params), q, std::move(as) ), base( b ) {} 125 129 126 // --- UnionInstType 130 template<typename decl_t> 131 bool SueInstType<decl_t>::isComplete() const { 132 return base ? base->body : false; 133 } 127 134 128 UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q, 129 std::vector<ptr<Attribute>>&& as ) 130 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {} 131 132 bool UnionInstType::isComplete() const { return base ? base->body : false; } 133 134 // --- EnumInstType 135 136 EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q, 137 std::vector<ptr<Attribute>>&& as ) 138 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {} 139 140 bool EnumInstType::isComplete() const { return base ? base->body : false; } 135 template class SueInstType<StructDecl>; 136 template class SueInstType<UnionDecl>; 137 template class SueInstType<EnumDecl>; 141 138 142 139 // --- TraitInstType 143 140 144 TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q, 145 std::vector<ptr<Attribute>>&& as ) 146 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {} 147 148 // --- TypeInstType 141 TraitInstType::TraitInstType( 142 const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 143 : BaseInstType( b->name, q, move(as) ), base( b ) {} 149 144 150 145 void TypeInstType::set_base( const TypeDecl * b ) { … … 158 153 159 154 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q ) 160 : Type( q ), types( std::move(ts) ), members() {155 : Type( q ), types( move(ts) ), members() { 161 156 // This constructor is awkward. `TupleType` needs to contain objects so that members can be 162 157 // named, but members without initializer nodes end up getting constructors, which breaks … … 173 168 for ( const Type * ty : types ) { 174 169 members.emplace_back( new ObjectDecl{ 175 CodeLocation{}, "", ty, new ListInit( CodeLocation{}, {}, {}, MaybeConstruct ),170 CodeLocation{}, "", ty, new ListInit( CodeLocation{}, {}, {}, NoConstruct ), 176 171 Storage::Classes{}, Linkage::Cforall } ); 177 172 } 173 } 174 175 bool isUnboundType(const Type * type) { 176 if (auto typeInst = dynamic_cast<const TypeInstType *>(type)) { 177 // xxx - look for a type name produced by renameTyVars. 178 179 // TODO: once TypeInstType representation is updated, it should properly check 180 // if the context id is filled. this is a temporary hack for now 181 return typeInst->formal_usage > 0; 182 } 183 return false; 178 184 } 179 185 -
src/AST/Type.hpp
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Thu May 9 10:00:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Dec 11 21:56:46 201913 // Update Count : 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Jul 23 14:15:00 2020 13 // Update Count : 6 14 14 // 15 15 … … 29 29 30 30 // Must be included in *all* AST classes; should be #undef'd at the end of the file 31 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 31 #define MUTATE_FRIEND \ 32 template<typename node_t> friend node_t * mutate(const node_t * node); \ 33 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 32 34 33 35 namespace ast { 36 37 template< typename T > class Pass; 34 38 35 39 class Type : public Node { … … 44 48 bool is_volatile() const { return qualifiers.is_volatile; } 45 49 bool is_restrict() const { return qualifiers.is_restrict; } 46 bool is_lvalue() const { return qualifiers.is_lvalue; }47 50 bool is_mutex() const { return qualifiers.is_mutex; } 48 51 bool is_atomic() const { return qualifiers.is_atomic; } … … 51 54 Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; } 52 55 Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; } 53 Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }54 56 Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; } 55 57 Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; } … … 163 165 static const char *typeNames[]; 164 166 165 BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 167 BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 166 168 : Type(q, std::move(as)), kind(k) {} 167 169 … … 263 265 }; 264 266 265 /// Base type for potentially forall-qualified types266 class ParameterizedType : public Type {267 public:268 using ForallList = std::vector<ptr<TypeDecl>>;269 270 ForallList forall;271 272 ParameterizedType( ForallList&& fs = {}, CV::Qualifiers q = {},273 std::vector<ptr<Attribute>> && as = {} )274 : Type(q, std::move(as)), forall(std::move(fs)) {}275 276 ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )277 : Type(q, std::move(as)), forall() {}278 279 private:280 virtual ParameterizedType * clone() const override = 0;281 MUTATE_FRIEND282 };283 284 267 /// Function variable arguments flag 285 268 enum ArgumentFlag { FixedArgs, VariableArgs }; 286 269 287 270 /// Type of a function `[R1, R2](*)(P1, P2, P3)` 288 class FunctionType final : public ParameterizedType { 289 public: 290 std::vector<ptr<DeclWithType>> returns; 291 std::vector<ptr<DeclWithType>> params; 271 class FunctionType final : public Type { 272 public: 273 using ForallList = std::vector<ptr<TypeInstType>>; 274 using AssertionList = std::vector<ptr<VariableExpr>>; 275 ForallList forall; 276 AssertionList assertions; 277 278 std::vector<ptr<Type>> returns; 279 std::vector<ptr<Type>> params; 292 280 293 281 /// Does the function accept a variable number of arguments following the arguments specified … … 299 287 300 288 FunctionType( ArgumentFlag va = FixedArgs, CV::Qualifiers q = {} ) 301 : ParameterizedType(q), returns(), params(), isVarArgs(va) {} 289 : Type(q), returns(), params(), isVarArgs(va) {} 290 291 FunctionType( const FunctionType & o ) = default; 302 292 303 293 /// true if either the parameters or return values contain a tttype … … 313 303 314 304 /// base class for types that refer to types declared elsewhere (aggregates and typedefs) 315 class ReferenceToType : public ParameterizedType {305 class BaseInstType : public Type { 316 306 public: 317 307 std::vector<ptr<Expr>> params; … … 319 309 bool hoistType = false; 320 310 321 ReferenceToType( const std::string& n, CV::Qualifiers q = {}, 322 std::vector<ptr<Attribute>> && as = {} ) 323 : ParameterizedType(q, std::move(as)), params(), name(n) {} 311 BaseInstType( 312 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 313 : Type(q, std::move(as)), params(), name(n) {} 314 315 BaseInstType( 316 const std::string& n, std::vector<ptr<Expr>> && params, 317 CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 318 : Type(q, std::move(as)), params(std::move(params)), name(n) {} 319 320 BaseInstType( const BaseInstType & o ) = default; 324 321 325 322 /// Gets aggregate declaration this type refers to … … 329 326 330 327 private: 331 virtual ReferenceToType * clone() const override = 0; 332 MUTATE_FRIEND 333 }; 334 335 /// instance of struct type 336 class StructInstType final : public ReferenceToType { 337 public: 338 readonly<StructDecl> base; 339 340 StructInstType( const std::string& n, CV::Qualifiers q = {}, 341 std::vector<ptr<Attribute>> && as = {} ) 342 : ReferenceToType( n, q, std::move(as) ), base() {} 343 StructInstType( const StructDecl * b, CV::Qualifiers q = {}, 344 std::vector<ptr<Attribute>> && as = {} ); 328 virtual BaseInstType * clone() const override = 0; 329 MUTATE_FRIEND 330 }; 331 332 // Common implementation for the SUE instance types. Not to be used directly. 333 template<typename decl_t> 334 class SueInstType final : public BaseInstType { 335 public: 336 using base_type = decl_t; 337 readonly<decl_t> base; 338 339 SueInstType( 340 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 341 : BaseInstType( n, q, std::move(as) ), base() {} 342 343 SueInstType( 344 const base_type * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 345 346 SueInstType( 347 const base_type * b, std::vector<ptr<Expr>> && params, 348 CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 345 349 346 350 bool isComplete() const override; 347 351 348 const StructDecl * aggr() const override { return base; } 349 350 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 351 private: 352 StructInstType * clone() const override { return new StructInstType{ *this }; } 353 MUTATE_FRIEND 354 }; 355 356 /// instance of union type 357 class UnionInstType final : public ReferenceToType { 358 public: 359 readonly<UnionDecl> base; 360 361 UnionInstType( const std::string& n, CV::Qualifiers q = {}, 362 std::vector<ptr<Attribute>> && as = {} ) 363 : ReferenceToType( n, q, std::move(as) ), base() {} 364 UnionInstType( const UnionDecl * b, CV::Qualifiers q = {}, 365 std::vector<ptr<Attribute>> && as = {} ); 366 367 bool isComplete() const override; 368 369 const UnionDecl * aggr() const override { return base; } 370 371 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 372 private: 373 UnionInstType * clone() const override { return new UnionInstType{ *this }; } 374 MUTATE_FRIEND 375 }; 376 377 /// instance of enum type 378 class EnumInstType final : public ReferenceToType { 379 public: 380 readonly<EnumDecl> base; 381 382 EnumInstType( const std::string& n, CV::Qualifiers q = {}, 383 std::vector<ptr<Attribute>> && as = {} ) 384 : ReferenceToType( n, q, std::move(as) ), base() {} 385 EnumInstType( const EnumDecl * b, CV::Qualifiers q = {}, 386 std::vector<ptr<Attribute>> && as = {} ); 387 388 bool isComplete() const override; 389 390 const EnumDecl * aggr() const override { return base; } 391 392 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 393 private: 394 EnumInstType * clone() const override { return new EnumInstType{ *this }; } 395 MUTATE_FRIEND 396 }; 397 398 /// instance of trait type 399 class TraitInstType final : public ReferenceToType { 352 const decl_t * aggr() const override { return base; } 353 354 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 355 private: 356 SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; } 357 MUTATE_FRIEND 358 }; 359 360 /// An instance of a struct type. 361 using StructInstType = SueInstType<StructDecl>; 362 363 /// An instance of a union type. 364 using UnionInstType = SueInstType<UnionDecl>; 365 366 /// An instance of an enum type. 367 using EnumInstType = SueInstType<EnumDecl>; 368 369 /// An instance of a trait type. 370 class TraitInstType final : public BaseInstType { 400 371 public: 401 372 readonly<TraitDecl> base; 402 373 403 TraitInstType( const std::string& n, CV::Qualifiers q = {}, 404 std::vector<ptr<Attribute>> && as = {} ) 405 : ReferenceToType( n, q, std::move(as) ), base() {} 406 TraitInstType( const TraitDecl * b, CV::Qualifiers q = {}, 407 std::vector<ptr<Attribute>> && as = {} ); 374 TraitInstType( 375 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 376 : BaseInstType( n, q, std::move(as) ), base() {} 377 378 TraitInstType( 379 const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 408 380 409 381 // not meaningful for TraitInstType … … 419 391 420 392 /// instance of named type alias (typedef or variable) 421 class TypeInstType final : public ReferenceToType {393 class TypeInstType final : public BaseInstType { 422 394 public: 423 395 readonly<TypeDecl> base; 396 // previously from renameTyVars; now directly use integer fields instead of synthesized strings 397 // a nonzero value of formal_usage indicates a formal type (only used in function type) 398 // a zero value of formal_usage indicates an actual type (referenced inside body of parametric structs and functions) 424 399 TypeDecl::Kind kind; 425 426 TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 400 int formal_usage = 0; 401 int expr_id = 0; 402 403 // compact representation used for map lookups. 404 struct TypeEnvKey { 405 const TypeDecl * base; 406 int formal_usage; 407 int expr_id; 408 409 TypeEnvKey() = default; 410 TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0): base(base), formal_usage(formal_usage), expr_id(expr_id) {} 411 TypeEnvKey(const TypeInstType & inst): base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {} 412 std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; } 413 bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; } 414 415 }; 416 417 bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; } 418 419 TypeInstType( 420 const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 427 421 std::vector<ptr<Attribute>> && as = {} ) 428 : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}422 : BaseInstType( n, q, std::move(as) ), base( b ), kind( b->kind ) {} 429 423 TypeInstType( const std::string& n, TypeDecl::Kind k, CV::Qualifiers q = {}, 430 424 std::vector<ptr<Attribute>> && as = {} ) 431 : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {} 425 : BaseInstType( n, q, std::move(as) ), base(), kind( k ) {} 426 427 TypeInstType( const TypeInstType & o ) = default; 428 429 TypeInstType( const TypeEnvKey & key ) 430 : BaseInstType(key.base->name), base(key.base), kind(key.base->kind), formal_usage(key.formal_usage), expr_id(key.expr_id) {} 432 431 433 432 /// sets `base`, updating `kind` correctly … … 440 439 441 440 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 441 442 std::string typeString() const { 443 if (formal_usage > 0) return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + name; 444 else return name; 445 } 442 446 private: 443 447 TypeInstType * clone() const override { return new TypeInstType{ *this }; } … … 531 535 }; 532 536 537 bool isUnboundType(const Type * type); 538 539 } 540 541 namespace std { 542 template<> 543 struct hash<typename ast::TypeInstType::TypeEnvKey> { 544 size_t operator() (const ast::TypeInstType::TypeEnvKey & x) const { 545 const size_t p = 1000007; 546 size_t res = reinterpret_cast<size_t>(x.base); 547 res = p * res + x.formal_usage; 548 res = p * res + x.expr_id; 549 return res; 550 } 551 }; 533 552 } 534 553 -
src/AST/TypeEnvironment.cpp
rbdfc032 reef8dfb 34 34 #include "ResolvExpr/Unify.h" // for unifyInexact 35 35 #include "Tuples/Tuples.h" // for isTtype 36 #include "CompilationState.h" 36 37 37 38 using ResolvExpr::WidenMode; … … 51 52 for ( const auto & i : open ) { 52 53 if ( first ) { first = false; } else { out << ' '; } 53 out << i.first << "(" << i.second << ")";54 out << i.first.typeString() << "(" << i.second << ")"; 54 55 } 55 56 } 56 57 57 58 void print( std::ostream & out, const EqvClass & clz, Indenter indent ) { 58 out << "( "; 59 std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) ); 59 out << "("; 60 bool first = true; 61 for(const auto & var : clz.vars) { 62 if(first) first = false; 63 else out << " "; 64 65 if( deterministic_output ) out << "[unbound]"; 66 else out << "_" << var.formal_usage << "_" << var.expr_id << "_"; 67 68 out << var.base->name; 69 } 60 70 out << ")"; 61 71 62 72 if ( clz.bound ) { 63 73 out << " -> "; … … 72 82 } 73 83 74 const EqvClass * TypeEnvironment::lookup( const std::string& var ) const {84 const EqvClass * TypeEnvironment::lookup( const TypeInstType::TypeEnvKey & var ) const { 75 85 for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) { 76 86 if ( i->vars.find( var ) != i->vars.end() ) return &*i; … … 92 102 } 93 103 } 94 104 95 105 i = next; // go to next node even if this removed 96 106 } … … 98 108 } 99 109 100 void TypeEnvironment::add( const ParameterizedType::ForallList & tyDecls ) {101 for ( const TypeDecl *tyDecl : tyDecls ) {110 void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) { 111 for ( auto & tyDecl : tyDecls ) { 102 112 env.emplace_back( tyDecl ); 103 113 } … … 112 122 void TypeEnvironment::writeToSubstitution( TypeSubstitution & sub ) const { 113 123 for ( const auto & clz : env ) { 114 std::string clzRep; 124 TypeInstType::TypeEnvKey clzRep; 125 bool first = true; 115 126 for ( const auto & var : clz.vars ) { 116 127 if ( clz.bound ) { 117 128 sub.add( var, clz.bound ); 118 } else if ( clzRep.empty()) {129 } else if ( first ) { 119 130 clzRep = var; 131 first = false; 120 132 } else { 121 sub.add( var, new TypeInstType{ clzRep , clz.data.kind} );133 sub.add( var, new TypeInstType{ clzRep } ); 122 134 } 123 135 } … … 134 146 struct Occurs : public ast::WithVisitorRef<Occurs> { 135 147 bool result; 136 std:: set< std::string> vars;148 std::unordered_set< TypeInstType::TypeEnvKey > vars; 137 149 const TypeEnvironment & tenv; 138 150 139 Occurs( const std::string& var, const TypeEnvironment & env )151 Occurs( const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env ) 140 152 : result( false ), vars(), tenv( env ) { 141 153 if ( const EqvClass * clz = tenv.lookup( var ) ) { … … 147 159 148 160 void previsit( const TypeInstType * typeInst ) { 149 if ( vars.count( typeInst->name) ) {161 if ( vars.count( *typeInst ) ) { 150 162 result = true; 151 } else if ( const EqvClass * clz = tenv.lookup( typeInst->name) ) {163 } else if ( const EqvClass * clz = tenv.lookup( *typeInst ) ) { 152 164 if ( clz->bound ) { 153 165 clz->bound->accept( *visitor ); … … 158 170 159 171 /// true if `var` occurs in `ty` under `env` 160 bool occurs( const Type * ty, const std::string& var, const TypeEnvironment & env ) {172 bool occurs( const Type * ty, const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env ) { 161 173 Pass<Occurs> occur{ var, env }; 162 174 maybe_accept( ty, occur ); 163 return occur. pass.result;164 } 165 } 166 167 bool TypeEnvironment::combine( 175 return occur.core.result; 176 } 177 } 178 179 bool TypeEnvironment::combine( 168 180 const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) { 169 181 // short-circuit easy cases … … 199 211 auto st = internal_lookup( *vt ); 200 212 if ( st == env.end() ) { 201 // unbound, safe to add if occurs 213 // unbound, safe to add if occurs 202 214 if ( r.bound && occurs( r.bound, *vt, *this ) ) return false; 203 215 r.vars.emplace( *vt ); … … 266 278 } 267 279 268 bool TypeEnvironment::bindVar( 269 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 270 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 271 const SymbolTable & symtab 280 bool TypeEnvironment::bindVar( 281 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 282 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 283 const SymbolTable & symtab 272 284 ) { 273 285 // remove references from bound type, so that type variables can only bind to value types 274 286 ptr<Type> target = bindTo->stripReferences(); 275 auto tyvar = open.find( typeInst->name);287 auto tyvar = open.find( *typeInst ); 276 288 assert( tyvar != open.end() ); 277 289 if ( ! tyVarCompatible( tyvar->second, target ) ) return false; 278 if ( occurs( target, typeInst->name, *this ) ) return false;279 280 auto it = internal_lookup( typeInst->name);290 if ( occurs( target, *typeInst, *this ) ) return false; 291 292 auto it = internal_lookup( *typeInst ); 281 293 if ( it != env.end() ) { 282 294 if ( it->bound ) { … … 286 298 ptr<Type> newType = it->bound; 287 299 reset_qualifiers( newType, typeInst->qualifiers ); 288 if ( unifyInexact( 289 newType, target, *this, need, have, open, 300 if ( unifyInexact( 301 newType, target, *this, need, have, open, 290 302 widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) { 291 303 if ( common ) { … … 300 312 } 301 313 } else { 302 env.emplace_back( 303 typeInst->name, target, widen.first && widen.second, data );314 env.emplace_back( 315 *typeInst, target, widen.first && widen.second, data ); 304 316 } 305 317 return true; 306 318 } 307 319 308 bool TypeEnvironment::bindVarToVar( 309 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 310 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 311 WidenMode widen, const SymbolTable & symtab 320 bool TypeEnvironment::bindVarToVar( 321 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 322 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 323 WidenMode widen, const SymbolTable & symtab 312 324 ) { 313 auto c1 = internal_lookup( var1->name);314 auto c2 = internal_lookup( var2->name);315 325 auto c1 = internal_lookup( *var1 ); 326 auto c2 = internal_lookup( *var2 ); 327 316 328 // exit early if variables already bound together 317 329 if ( c1 != env.end() && c1 == c2 ) { … … 326 338 if ( c1 != env.end() ) { 327 339 if ( c1->bound ) { 328 if ( occurs( c1->bound, var2->name, *this ) ) return false;340 if ( occurs( c1->bound, *var2, *this ) ) return false; 329 341 type1 = c1->bound; 330 342 } … … 333 345 if ( c2 != env.end() ) { 334 346 if ( c2->bound ) { 335 if ( occurs( c2->bound, var1->name, *this ) ) return false;347 if ( occurs( c2->bound, *var1, *this ) ) return false; 336 348 type2 = c2->bound; 337 349 } … … 371 383 } else if ( c1 != env.end() ) { 372 384 // var2 unbound, add to env[c1] 373 c1->vars.emplace( var2->name);385 c1->vars.emplace( *var2 ); 374 386 c1->allowWidening = widen1; 375 387 c1->data.isComplete |= data.isComplete; 376 388 } else if ( c2 != env.end() ) { 377 389 // var1 unbound, add to env[c2] 378 c2->vars.emplace( var1->name);390 c2->vars.emplace( *var1 ); 379 391 c2->allowWidening = widen2; 380 392 c2->data.isComplete |= data.isComplete; 381 393 } else { 382 394 // neither var bound, create new class 383 env.emplace_back( var1->name, var2->name, widen1 && widen2, data );395 env.emplace_back( *var1, *var2, widen1 && widen2, data ); 384 396 } 385 397 … … 396 408 } 397 409 398 bool TypeEnvironment::mergeBound( 410 bool TypeEnvironment::mergeBound( 399 411 EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) { 400 412 if ( from.bound ) { … … 406 418 AssertionSet need, have; 407 419 408 if ( unifyInexact( 420 if ( unifyInexact( 409 421 toType, fromType, *this, need, have, open, widen, symtab, common ) ) { 410 422 // unifies, set common type if necessary … … 424 436 } 425 437 426 bool TypeEnvironment::mergeClasses( 438 bool TypeEnvironment::mergeClasses( 427 439 ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab 428 440 ) { … … 445 457 } 446 458 447 TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string& var ) {459 TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const TypeInstType::TypeEnvKey & var ) { 448 460 for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) { 449 461 if ( i->vars.count( var ) ) return i; -
src/AST/TypeEnvironment.hpp
rbdfc032 reef8dfb 37 37 /// Adding this comparison operator significantly improves assertion satisfaction run time for 38 38 /// some cases. The current satisfaction algorithm's speed partially depends on the order of 39 /// assertions. Assertions which have fewer possible matches should appear before assertions 40 /// which have more possible matches. This seems to imply that this could be further improved 41 /// by providing an indexer as an additional argument and ordering based on the number of 39 /// assertions. Assertions which have fewer possible matches should appear before assertions 40 /// which have more possible matches. This seems to imply that this could be further improved 41 /// by providing an indexer as an additional argument and ordering based on the number of 42 42 /// matches of the same kind (object, function) for the names of the declarations. 43 43 /// 44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 45 45 /// comparator. 46 46 /// 47 /// Note: since this compares pointers for position, minor changes in the source file that 48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 49 /// placement of a line directive can reorder type pointers with respect to each other so that 50 /// assertions are seen in different orders, causing a potentially different number of 51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 54 /// name instead of type as the second comparator, but this causes some assertions to never be 47 /// Note: since this compares pointers for position, minor changes in the source file that 48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 49 /// placement of a line directive can reorder type pointers with respect to each other so that 50 /// assertions are seen in different orders, causing a potentially different number of 51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 54 /// name instead of type as the second comparator, but this causes some assertions to never be 55 55 /// recorded. More investigation is needed. 56 56 struct AssertCompare { 57 bool operator()( const DeclWithType * d1, const DeclWithType* d2 ) const {58 int cmp = d1-> name.compare( d2->name );59 return cmp < 0 || ( cmp == 0 && d1-> get_type() < d2->get_type());57 bool operator()( const VariableExpr * d1, const VariableExpr * d2 ) const { 58 int cmp = d1->var->name.compare( d2->var->name ); 59 return cmp < 0 || ( cmp == 0 && d1->result < d2->result ); 60 60 } 61 61 }; … … 70 70 71 71 /// Set of assertions pending satisfaction 72 using AssertionSet = std::map< readonly<DeclWithType>, AssertionSetValue, AssertCompare >;72 using AssertionSet = std::map< const VariableExpr *, AssertionSetValue, AssertCompare >; 73 73 74 74 /// Set of open variables 75 using OpenVarSet = std::unordered_map< std::string, TypeDecl::Data >;75 using OpenVarSet = std::unordered_map< TypeInstType::TypeEnvKey, TypeDecl::Data >; 76 76 77 77 /// Merges one set of open vars into another … … 86 86 void print( std::ostream &, const OpenVarSet &, Indenter indent = {} ); 87 87 88 /// Represents an equivalence class of bound type variables, optionally with the concrete type 88 /// Represents an equivalence class of bound type variables, optionally with the concrete type 89 89 /// they bind to. 90 90 struct EqvClass { 91 std:: set< std::string> vars;91 std::unordered_set< TypeInstType::TypeEnvKey > vars; 92 92 ptr<Type> bound; 93 93 bool allowWidening; … … 95 95 96 96 EqvClass() : vars(), bound(), allowWidening( true ), data() {} 97 97 98 98 /// Copy-with-bound constructor 99 EqvClass( const EqvClass & o, const Type * b ) 99 EqvClass( const EqvClass & o, const Type * b ) 100 100 : vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {} 101 101 102 102 /// Singleton class constructor from TypeDecl 103 EqvClass( const Type Decl * decl)104 : vars{ decl->name }, bound(), allowWidening( true ), data( decl) {}103 EqvClass( const TypeInstType * inst ) 104 : vars{ *inst }, bound(), allowWidening( true ), data( inst->base ) {} 105 105 106 106 /// Singleton class constructor from substitution 107 EqvClass( const std::string& v, const Type * b )107 EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b ) 108 108 : vars{ v }, bound( b ), allowWidening( false ), data( TypeDecl::Dtype, false ) {} 109 109 110 110 /// Single-var constructor (strips qualifiers from bound type) 111 EqvClass( const std::string& v, const Type * b, bool w, const TypeDecl::Data & d )111 EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b, bool w, const TypeDecl::Data & d ) 112 112 : vars{ v }, bound( b ), allowWidening( w ), data( d ) { 113 113 reset_qualifiers( bound ); … … 115 115 116 116 /// Double-var constructor 117 EqvClass( const std::string & v, const std::string& u, bool w, const TypeDecl::Data & d )117 EqvClass( const TypeInstType::TypeEnvKey & v, const TypeInstType::TypeEnvKey & u, bool w, const TypeDecl::Data & d ) 118 118 : vars{ v, u }, bound(), allowWidening( w ), data( d ) {} 119 119 … … 131 131 public: 132 132 /// Finds the equivalence class containing a variable; nullptr for none such 133 const EqvClass * lookup( const std::string& var ) const;133 const EqvClass * lookup( const TypeInstType::TypeEnvKey & var ) const; 134 134 135 135 /// Add a new equivalence class for each type variable 136 void add( const ParameterizedType::ForallList & tyDecls );136 void add( const FunctionType::ForallList & tyDecls ); 137 137 138 138 /// Add a new equivalence class for each branch of the substitution, checking for conflicts … … 142 142 void writeToSubstitution( TypeSubstitution & sub ) const; 143 143 144 template< typename node_t , enum Node::ref_type ref_t>145 int apply( ptr_base< node_t, ref_t >& type ) const {144 template< typename node_t > 145 auto apply( node_t && type ) const { 146 146 TypeSubstitution sub; 147 147 writeToSubstitution( sub ); 148 return sub.apply( type);149 } 150 151 template< typename node_t , enum Node::ref_type ref_t>152 int applyFree( ptr_base< node_t, ref_t >& type ) const {148 return sub.apply( std::forward<node_t>(type) ); 149 } 150 151 template< typename node_t > 152 auto applyFree( node_t && type ) const { 153 153 TypeSubstitution sub; 154 154 writeToSubstitution( sub ); 155 return sub.applyFree( type);155 return sub.applyFree( std::forward<node_t>(type) ); 156 156 } 157 157 … … 172 172 void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars ); 173 173 174 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 174 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 175 175 /// needed. Returns false on failure. 176 bool bindVar( 177 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 178 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 176 bool bindVar( 177 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 178 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 179 179 ResolvExpr::WidenMode widen, const SymbolTable & symtab ); 180 181 /// Binds the type classes represented by `var1` and `var2` together; will add one or both 180 181 /// Binds the type classes represented by `var1` and `var2` together; will add one or both 182 182 /// classes if needed. Returns false on failure. 183 bool bindVarToVar( 184 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 185 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 183 bool bindVarToVar( 184 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 185 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 186 186 ResolvExpr::WidenMode widen, const SymbolTable & symtab ); 187 187 … … 198 198 199 199 /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails 200 bool mergeBound( 200 bool mergeBound( 201 201 EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab ); 202 202 203 203 /// Merges two type classes from local environment, returning false if fails 204 bool mergeClasses( 205 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 204 bool mergeClasses( 205 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 206 206 const SymbolTable & symtab ); 207 207 208 208 /// Private lookup API; returns array index of string, or env.size() for not found 209 ClassList::iterator internal_lookup( const std::string& );209 ClassList::iterator internal_lookup( const TypeInstType::TypeEnvKey & ); 210 210 }; 211 211 -
src/AST/TypeSubstitution.cpp
rbdfc032 reef8dfb 19 19 namespace ast { 20 20 21 22 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution"); 23 21 24 TypeSubstitution::TypeSubstitution() { 22 25 } … … 36 39 void TypeSubstitution::initialize( const TypeSubstitution &src, TypeSubstitution &dest ) { 37 40 dest.typeEnv.clear(); 38 dest.varEnv.clear();39 41 dest.add( src ); 40 42 } … … 44 46 typeEnv[ i->first ] = i->second; 45 47 } // for 46 for ( VarEnvType::const_iterator i = other.varEnv.begin(); i != other.varEnv.end(); ++i ) {47 varEnv[ i->first ] = i->second;48 } // for49 48 } 50 49 51 void TypeSubstitution::add( std::stringformalType, const Type *actualType ) {52 typeEnv[ formalType ] = actualType;50 void TypeSubstitution::add( const TypeInstType * formalType, const Type *actualType ) { 51 typeEnv[ *formalType ] = actualType; 53 52 } 54 53 55 void TypeSubstitution::add Var( std::string formalExpr, const Expr *actualExpr) {56 varEnv[ formalExpr ] = actualExpr;54 void TypeSubstitution::add( const TypeInstType::TypeEnvKey & key, const Type * actualType) { 55 typeEnv[ key ] = actualType; 57 56 } 58 57 59 void TypeSubstitution::remove( std::stringformalType ) {60 TypeEnvType::iterator i = typeEnv.find( formalType );58 void TypeSubstitution::remove( const TypeInstType * formalType ) { 59 TypeEnvType::iterator i = typeEnv.find( *formalType ); 61 60 if ( i != typeEnv.end() ) { 62 typeEnv.erase( formalType );61 typeEnv.erase( *formalType ); 63 62 } // if 64 63 } 65 64 66 const Type *TypeSubstitution::lookup( std::stringformalType ) const {67 TypeEnvType::const_iterator i = typeEnv.find( formalType );65 const Type *TypeSubstitution::lookup( const TypeInstType * formalType ) const { 66 TypeEnvType::const_iterator i = typeEnv.find( *formalType ); 68 67 69 68 // break on not in substitution set … … 72 71 // attempt to transitively follow TypeInstType links. 73 72 while ( const TypeInstType *actualType = i->second.as<TypeInstType>()) { 74 const std::string& typeName = actualType->name;75 76 73 // break cycles in the transitive follow 77 if ( formalType == typeName ) break;74 if ( *formalType == *actualType ) break; 78 75 79 76 // Look for the type this maps to, returning previous mapping if none-such 80 i = typeEnv.find( typeName );77 i = typeEnv.find( *actualType ); 81 78 if ( i == typeEnv.end() ) return actualType; 82 79 } … … 87 84 88 85 bool TypeSubstitution::empty() const { 89 return typeEnv.empty() && varEnv.empty();86 return typeEnv.empty(); 90 87 } 91 88 92 89 namespace { 93 90 struct EnvTrimmer { 94 ptr<TypeSubstitution>env;91 const TypeSubstitution * env; 95 92 TypeSubstitution * newEnv; 96 93 EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} 97 void previsit( TypeDecl * tyDecl) {94 void previsit( FunctionType * ftype ) { 98 95 // transfer known bindings for seen type variables 99 if ( const Type * t = env->lookup( tyDecl->name ) ) { 100 newEnv->add( tyDecl->name, t ); 96 for (auto & formal : ftype->forall) { 97 if ( const Type * t = env->lookup( formal ) ) { 98 newEnv->add( formal, t ); 99 } 101 100 } 102 101 } … … 108 107 if ( env ) { 109 108 TypeSubstitution * newEnv = new TypeSubstitution(); 110 #if TIME_TO_CONVERT_PASSES111 109 Pass<EnvTrimmer> trimmer( env, newEnv ); 112 110 expr->accept( trimmer ); 113 #else114 (void)expr;115 (void)env;116 #endif117 111 return newEnv; 118 112 } … … 121 115 122 116 void TypeSubstitution::normalize() { 123 #if TIME_TO_CONVERT_PASSES 124 PassVisitor<Substituter> sub( *this, true ); 117 Pass<Substituter> sub( *this, true ); 125 118 do { 126 sub. pass.subCount = 0;127 sub. pass.freeOnly = true;119 sub.core.subCount = 0; 120 sub.core.freeOnly = true; 128 121 for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) { 129 i->second = i->second->accept Mutator( sub );122 i->second = i->second->accept( sub ); 130 123 } 131 } while ( sub.pass.subCount ); 132 #endif 124 } while ( sub.core.subCount ); 133 125 } 134 126 135 #if TIME_TO_CONVERT_PASSES 136 137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) { 138 BoundVarsType::const_iterator bound = boundVars.find( inst->name ); 127 const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) { 128 BoundVarsType::const_iterator bound = boundVars.find( *inst ); 139 129 if ( bound != boundVars.end() ) return inst; 140 130 141 TypeEnvType::const_iterator i = sub.typeEnv.find( inst->name);131 TypeEnvType::const_iterator i = sub.typeEnv.find( *inst ); 142 132 if ( i == sub.typeEnv.end() ) { 143 133 return inst; … … 146 136 // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here. 147 137 // TODO: investigate preventing type variables from being bound to themselves in the first place. 148 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {149 if ( inst->name == replacement->name) {138 if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) { 139 if ( *inst == *replacement ) { 150 140 return inst; 151 141 } … … 153 143 // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl; 154 144 subCount++; 155 Type * newtype = i->second->clone(); 156 newtype->get_qualifiers() |= inst->get_qualifiers(); 157 delete inst; 158 // Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 159 return newtype->acceptMutator( *visitor ); 145 ptr<Type> newType = i->second; // force clone if needed 146 add_qualifiers( newType, inst->qualifiers ); 147 // Note: need to recursively apply substitution to the new type because normalize does not 148 // substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 149 newType = newType->accept( *visitor ); 150 return newType.release(); 160 151 } // if 161 152 } 162 153 163 Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) { 164 VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name ); 165 if ( i == sub.varEnv.end() ) { 166 return nameExpr; 167 } else { 168 subCount++; 169 delete nameExpr; 170 return i->second->clone(); 171 } // if 172 } 173 174 void TypeSubstitution::Substituter::premutate( Type * type ) { 154 void TypeSubstitution::Substituter::previsit( const FunctionType * ptype ) { 175 155 GuardValue( boundVars ); 176 156 // bind type variables from forall-qualifiers 177 157 if ( freeOnly ) { 178 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {179 boundVars.insert( (*tyvar)->name);158 for ( auto & tyvar : ptype->forall ) { 159 boundVars.insert( *tyvar ); 180 160 } // for 181 161 } // if 182 162 } 183 163 184 template< typename TypeClass > 185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass* type ) {164 /* 165 void TypeSubstitution::Substituter::handleAggregateType( const BaseInstType * type ) { 186 166 GuardValue( boundVars ); 187 167 // bind type variables from forall-qualifiers 188 168 if ( freeOnly ) { 189 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {190 boundVars.insert( (*tyvar)->name );191 } // for192 169 // bind type variables from generic type instantiations 193 std::list< TypeDecl* > *baseParameters = type->get_baseParameters(); 194 if ( baseParameters && ! type->parameters.empty() ) { 195 for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) { 196 boundVars.insert( (*tyvar)->name ); 197 } // for 198 } // if 170 if ( auto decl = type->aggr() ) { 171 if ( ! type->params.empty() ) { 172 for ( const TypeDecl * tyvar : decl->params ) { 173 boundVars.insert( *tyvar ); 174 } // for 175 } // if 176 } 199 177 } // if 200 178 } 201 179 202 void TypeSubstitution::Substituter::pre mutate(StructInstType * aggregateUseType ) {180 void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) { 203 181 handleAggregateType( aggregateUseType ); 204 182 } 205 183 206 void TypeSubstitution::Substituter::pre mutate(UnionInstType *aggregateUseType ) {184 void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) { 207 185 handleAggregateType( aggregateUseType ); 208 186 } 209 210 #endif 187 */ 211 188 212 189 } // namespace ast -
src/AST/TypeSubstitution.hpp
rbdfc032 reef8dfb 44 44 TypeSubstitution &operator=( const TypeSubstitution &other ); 45 45 46 template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const; 47 template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const; 46 template< typename SynTreeClass > 47 struct ApplyResult { 48 ast::ptr<SynTreeClass> node; 49 int count; 50 }; 51 52 template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const; 53 template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const; 48 54 49 55 template< typename node_t, enum Node::ref_type ref_t > 50 56 int apply( ptr_base< node_t, ref_t > & input ) const { 51 57 const node_t * p = input.get(); 52 intret = apply(p);53 input = p;54 return ret ;58 auto ret = apply(p); 59 input = ret.node; 60 return ret.count; 55 61 } 56 62 … … 58 64 int applyFree( ptr_base< node_t, ref_t > & input ) const { 59 65 const node_t * p = input.get(); 60 intret = applyFree(p);61 input = p;62 return ret ;66 auto ret = applyFree(p); 67 input = ret.node; 68 return ret.count; 63 69 } 64 70 65 void add( std::string formalType, const Type *actualType ); 71 void add( const TypeInstType * formalType, const Type *actualType ); 72 void add( const TypeInstType::TypeEnvKey & key, const Type *actualType ); 66 73 void add( const TypeSubstitution &other ); 67 void remove( std::stringformalType );68 const Type *lookup( std::stringformalType ) const;74 void remove( const TypeInstType * formalType ); 75 const Type *lookup( const TypeInstType * formalType ) const; 69 76 bool empty() const; 70 71 void addVar( std::string formalExpr, const Expr *actualExpr );72 77 73 78 template< typename FormalIterator, typename ActualIterator > … … 92 97 void initialize( const TypeSubstitution &src, TypeSubstitution &dest ); 93 98 94 template<typename pass_type>99 template<typename core_t> 95 100 friend class Pass; 96 101 97 typedef std::unordered_map< std::string, ptr<Type> > TypeEnvType; 98 typedef std::unordered_map< std::string, ptr<Expr> > VarEnvType; 102 typedef std::unordered_map< TypeInstType::TypeEnvKey, ptr<Type> > TypeEnvType; 99 103 TypeEnvType typeEnv; 100 VarEnvType varEnv;101 104 102 105 public: … … 107 110 auto end() const -> decltype( typeEnv. end() ) { return typeEnv. end(); } 108 111 109 auto beginVar() -> decltype( varEnv.begin() ) { return varEnv.begin(); }110 auto endVar() -> decltype( varEnv. end() ) { return varEnv. end(); }111 auto beginVar() const -> decltype( varEnv.begin() ) { return varEnv.begin(); }112 auto endVar() const -> decltype( varEnv. end() ) { return varEnv. end(); }113 112 }; 114 113 114 // this is the only place where type parameters outside a function formal may be substituted. 115 115 template< typename FormalIterator, typename ActualIterator > 116 116 void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) { … … 123 123 if ( const TypeExpr *actual = actualIt->template as<TypeExpr>() ) { 124 124 if ( formal->name != "" ) { 125 typeEnv[ formal ->name] = actual->type;125 typeEnv[ formal ] = actual->type; 126 126 } // if 127 127 } else { … … 129 129 } // if 130 130 } else { 131 // TODO: type check the formal and actual parameters 132 if ( (*formalIt)->name != "" ) { 133 varEnv[ (*formalIt)->name ] = *actualIt; 134 } // if 131 135 132 } // if 136 133 } // for 137 134 } 135 136 138 137 139 138 template< typename FormalIterator, typename ActualIterator > … … 142 141 } 143 142 143 144 144 } // namespace ast 145 145 … … 147 147 // PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals. 148 148 #include "Pass.hpp" 149 #include "Copy.hpp" 149 150 150 151 namespace ast { 151 152 152 153 // definitition must happen after PassVisitor is included so that WithGuards can be used 153 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> { 154 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter>, public PureVisitor { 155 static size_t traceId; 154 156 155 157 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {} 156 158 157 #if TIME_TO_CONVERT_PASSES 158 159 Type * postmutate( TypeInstType * aggregateUseType ); 160 Expression * postmutate( NameExpr * nameExpr ); 159 const Type * postvisit( const TypeInstType * aggregateUseType ); 161 160 162 161 /// Records type variable bindings from forall-statements 163 void pre mutate(Type * type );162 void previsit( const FunctionType * type ); 164 163 /// Records type variable bindings from forall-statements and instantiations of generic types 165 template< typename TypeClass > void handleAggregateType( TypeClass* type );164 // void handleAggregateType( const BaseInstType * type ); 166 165 167 void premutate( StructInstType * aggregateUseType ); 168 void premutate( UnionInstType * aggregateUseType ); 169 170 #endif 166 // void previsit( const StructInstType * aggregateUseType ); 167 // void previsit( const UnionInstType * aggregateUseType ); 171 168 172 169 const TypeSubstitution & sub; 173 170 int subCount = 0; 174 171 bool freeOnly; 175 typedef std::unordered_set< std::string> BoundVarsType;172 typedef std::unordered_set< TypeInstType::TypeEnvKey > BoundVarsType; 176 173 BoundVarsType boundVars; 177 174 … … 179 176 180 177 template< typename SynTreeClass > 181 int TypeSubstitution::apply( const SynTreeClass *&input ) const {178 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const { 182 179 assert( input ); 183 180 Pass<Substituter> sub( *this, false ); 184 181 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) ); 185 /// std::cerr << "substitution result is: "; 186 /// newType->print( std::cerr ); 187 /// std::cerr << std::endl; 188 return sub.pass.subCount; 182 return { input, sub.core.subCount }; 189 183 } 190 184 191 185 template< typename SynTreeClass > 192 int TypeSubstitution::applyFree( const SynTreeClass *&input ) const {186 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const { 193 187 assert( input ); 194 188 Pass<Substituter> sub( *this, true ); 195 189 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) ); 196 /// std::cerr << "substitution result is: "; 197 /// newType->print( std::cerr ); 198 /// std::cerr << std::endl; 199 return sub.pass.subCount; 190 return { input, sub.core.subCount }; 200 191 } 201 192 -
src/AST/Visitor.hpp
rbdfc032 reef8dfb 47 47 virtual const ast::Stmt * visit( const ast::CatchStmt * ) = 0; 48 48 virtual const ast::Stmt * visit( const ast::FinallyStmt * ) = 0; 49 virtual const ast::Stmt * visit( const ast::SuspendStmt * ) = 0; 49 50 virtual const ast::Stmt * visit( const ast::WaitForStmt * ) = 0; 50 51 virtual const ast::Decl * visit( const ast::WithStmt * ) = 0; -
src/AST/module.mk
rbdfc032 reef8dfb 17 17 SRC_AST = \ 18 18 AST/AssertAcyclic.cpp \ 19 AST/AssertAcyclic.hpp \ 19 20 AST/Attribute.cpp \ 21 AST/Attribute.hpp \ 22 AST/Bitfield.hpp \ 23 AST/Chain.hpp \ 20 24 AST/Convert.cpp \ 25 AST/Convert.hpp \ 26 AST/Copy.hpp \ 27 AST/CVQualifiers.hpp \ 21 28 AST/Decl.cpp \ 29 AST/Decl.hpp \ 22 30 AST/DeclReplacer.cpp \ 31 AST/DeclReplacer.hpp \ 32 AST/Eval.hpp \ 23 33 AST/Expr.cpp \ 34 AST/Expr.hpp \ 35 AST/FunctionSpec.hpp \ 36 AST/Fwd.hpp \ 24 37 AST/GenericSubstitution.cpp \ 38 AST/GenericSubstitution.hpp \ 25 39 AST/Init.cpp \ 40 AST/Init.hpp \ 41 AST/Label.hpp \ 26 42 AST/LinkageSpec.cpp \ 43 AST/LinkageSpec.hpp \ 27 44 AST/Node.cpp \ 45 AST/Node.hpp \ 46 AST/ParseNode.hpp \ 28 47 AST/Pass.cpp \ 48 AST/Pass.hpp \ 49 AST/Pass.impl.hpp \ 50 AST/Pass.proto.hpp \ 29 51 AST/Print.cpp \ 52 AST/Print.hpp \ 30 53 AST/Stmt.cpp \ 54 AST/Stmt.hpp \ 55 AST/StorageClasses.hpp \ 31 56 AST/SymbolTable.cpp \ 57 AST/SymbolTable.hpp \ 58 AST/TranslationUnit.hpp \ 32 59 AST/Type.cpp \ 60 AST/Type.hpp \ 33 61 AST/TypeEnvironment.cpp \ 34 AST/TypeSubstitution.cpp 62 AST/TypeEnvironment.hpp \ 63 AST/TypeSubstitution.cpp \ 64 AST/TypeSubstitution.hpp \ 65 AST/Visitor.hpp 35 66 36 67 SRC += $(SRC_AST) -
src/AST/porting.md
rbdfc032 reef8dfb 30 30 * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0` 31 31 * `PassVisitor` is replaced with `ast::Pass` 32 * Most one shot uses can use `ast::Pass::run` and `ast::Pass::read`. 33 34 `WithConstTypeSubstitution` 35 * `env` => `typeSubs` 32 36 33 37 ## Structural Changes ## … … 47 51 template<typename node_t> 48 52 friend node_t * mutate(const node_t * node); 53 template<typename node_t> 54 friend node_t * shallowCopy(const node_t * node); 55 or equilant. 56 * You should use the `mutate` function where possible as it avoids extra copies. 57 * If you must copy use `shallowCopy` or `deepCopy` as required. 49 58 50 59 All leaves of the `Node` inheritance tree are now declared `final` … … 141 150 * allows `newObject` as just default settings 142 151 152 `FunctionDecl` 153 * `params` and `returns` added. 154 * Contain the declarations of the parameters and return variables. 155 * Types should match (even be shared with) the fields of `type`. 156 143 157 `NamedTypeDecl` 144 158 * `parameters` => `params` … … 149 163 `AggregateDecl` 150 164 * `parameters` => `params` 165 166 `StructDecl` 167 * `makeInst` replaced by better constructor on `StructInstType`. 151 168 152 169 `Expr` … … 240 257 * **TODO** move `kind`, `typeNames` into code generator 241 258 242 `ReferenceToType` 259 `ReferenceToType` => `BaseInstType` 243 260 * deleted `get_baseParameters()` from children 244 261 * replace with `aggr() ? aggr()->params : nullptr` … … 256 273 * `returnVals` => `returns` 257 274 * `parameters` => `params` 275 * Both now just point at types. 258 276 * `bool isVarArgs;` => `enum ArgumentFlag { FixedArgs, VariableArgs }; ArgumentFlag isVarArgs;` 277 278 `SueInstType` 279 * Template class, with specializations and using to implement some other types: 280 * `StructInstType`, `UnionInstType` & `EnumInstType` 259 281 260 282 `TypeInstType` -
src/CodeGen/CodeGenerator.cc
rbdfc032 reef8dfb 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:13:28 201913 // Update Count : 5 0812 // Last Modified On : Sun Feb 16 08:32:48 2020 13 // Update Count : 532 14 14 // 15 15 #include "CodeGenerator.h" … … 39 39 int CodeGenerator::tabsize = 4; 40 40 41 // the kinds of statements that would ideally be followed by whitespace41 // The kinds of statements that would ideally be followed by whitespace. 42 42 bool wantSpacing( Statement * stmt) { 43 43 return dynamic_cast< IfStmt * >( stmt ) || dynamic_cast< CompoundStmt * >( stmt ) || … … 78 78 } 79 79 80 /* Using updateLocation at the beginning of a node and endl 81 * within a node should become the method of formating. 82 */ 80 // Using updateLocation at the beginning of a node and endl within a node should become the method of formating. 83 81 void CodeGenerator::updateLocation( CodeLocation const & to ) { 84 82 // skip if linemarks shouldn't appear or if codelocation is unset … … 95 93 } else { 96 94 output << "\n# " << to.first_line << " \"" << to.filename 97 95 << "\"\n" << indent; 98 96 currentLocation = to; 99 97 } … … 122 120 // GCC builtins should always be printed unmangled 123 121 if ( options.pretty || decl->linkage.is_gcc_builtin ) return decl->name; 124 if ( decl->mangleName != "" ) {122 if ( LinkageSpec::isMangled(decl->linkage) && decl->mangleName != "" ) { 125 123 // need to incorporate scope level in order to differentiate names for destructors 126 124 return decl->get_scopedMangleName(); … … 131 129 132 130 void CodeGenerator::genAttributes( list< Attribute * > & attributes ) { 133 131 if ( attributes.empty() ) return; 134 132 output << "__attribute__ (("; 135 133 for ( list< Attribute * >::iterator attr( attributes.begin() );; ) { … … 140 138 output << ")"; 141 139 } // if 142 140 if ( ++attr == attributes.end() ) break; 143 141 output << ","; // separator 144 142 } // for … … 165 163 previsit( (BaseSyntaxNode *)node ); 166 164 GuardAction( [this, node](){ 167 if ( options.printExprTypes && node->result ) {168 output << " /* " << genType( node->result, "", options ) << " */ ";169 }170 } );165 if ( options.printExprTypes && node->result ) { 166 output << " /* " << genType( node->result, "", options ) << " */ "; 167 } 168 } ); 171 169 } 172 170 … … 399 397 extension( applicationExpr ); 400 398 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr* >( applicationExpr->get_function() ) ) { 401 OperatorInfoopInfo;402 if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( varExpr->get_var()->get_name(), opInfo) ) {399 const OperatorInfo * opInfo; 400 if ( varExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && ( opInfo = operatorLookup( varExpr->get_var()->get_name() ) ) ) { 403 401 std::list< Expression* >::iterator arg = applicationExpr->get_args().begin(); 404 switch ( opInfo .type ) {402 switch ( opInfo->type ) { 405 403 case OT_INDEX: 406 404 assert( applicationExpr->get_args().size() == 2 ); … … 423 421 output << "("; 424 422 (*arg++)->accept( *visitor ); 425 output << ") /* " << opInfo .inputName << " */";423 output << ") /* " << opInfo->inputName << " */"; 426 424 } else if ( applicationExpr->get_args().size() == 2 ) { 427 425 // intrinsic two parameter constructors are essentially bitwise assignment 428 426 output << "("; 429 427 (*arg++)->accept( *visitor ); 430 output << opInfo .symbol;428 output << opInfo->symbol; 431 429 (*arg)->accept( *visitor ); 432 output << ") /* " << opInfo .inputName << " */";430 output << ") /* " << opInfo->inputName << " */"; 433 431 } else { 434 432 // no constructors with 0 or more than 2 parameters … … 441 439 assert( applicationExpr->get_args().size() == 1 ); 442 440 output << "("; 443 output << opInfo .symbol;441 output << opInfo->symbol; 444 442 (*arg)->accept( *visitor ); 445 443 output << ")"; … … 450 448 assert( applicationExpr->get_args().size() == 1 ); 451 449 (*arg)->accept( *visitor ); 452 output << opInfo .symbol;450 output << opInfo->symbol; 453 451 break; 454 452 … … 459 457 output << "("; 460 458 (*arg++)->accept( *visitor ); 461 output << opInfo .symbol;459 output << opInfo->symbol; 462 460 (*arg)->accept( *visitor ); 463 461 output << ")"; … … 486 484 extension( untypedExpr ); 487 485 if ( NameExpr * nameExpr = dynamic_cast< NameExpr* >( untypedExpr->function ) ) { 488 OperatorInfo opInfo;489 if ( op eratorLookup( nameExpr->name, opInfo )) {486 const OperatorInfo * opInfo = operatorLookup( nameExpr->name ); 487 if ( opInfo ) { 490 488 std::list< Expression* >::iterator arg = untypedExpr->args.begin(); 491 switch ( opInfo .type ) {489 switch ( opInfo->type ) { 492 490 case OT_INDEX: 493 491 assert( untypedExpr->args.size() == 2 ); … … 508 506 output << "("; 509 507 (*arg++)->accept( *visitor ); 510 output << ") /* " << opInfo .inputName << " */";508 output << ") /* " << opInfo->inputName << " */"; 511 509 } else if ( untypedExpr->get_args().size() == 2 ) { 512 510 // intrinsic two parameter constructors are essentially bitwise assignment 513 511 output << "("; 514 512 (*arg++)->accept( *visitor ); 515 output << opInfo .symbol;513 output << opInfo->symbol; 516 514 (*arg)->accept( *visitor ); 517 output << ") /* " << opInfo .inputName << " */";515 output << ") /* " << opInfo->inputName << " */"; 518 516 } else { 519 517 // no constructors with 0 or more than 2 parameters … … 521 519 output << "("; 522 520 (*arg++)->accept( *visitor ); 523 output << opInfo .symbol << "{ ";521 output << opInfo->symbol << "{ "; 524 522 genCommaList( arg, untypedExpr->args.end() ); 525 output << "}) /* " << opInfo .inputName << " */";523 output << "}) /* " << opInfo->inputName << " */"; 526 524 } // if 527 525 break; … … 532 530 assert( untypedExpr->args.size() == 1 ); 533 531 output << "("; 534 output << opInfo .symbol;532 output << opInfo->symbol; 535 533 (*arg)->accept( *visitor ); 536 534 output << ")"; … … 541 539 assert( untypedExpr->args.size() == 1 ); 542 540 (*arg)->accept( *visitor ); 543 output << opInfo .symbol;541 output << opInfo->symbol; 544 542 break; 545 543 … … 549 547 output << "("; 550 548 (*arg++)->accept( *visitor ); 551 output << opInfo .symbol;549 output << opInfo->symbol; 552 550 (*arg)->accept( *visitor ); 553 551 output << ")"; … … 581 579 void CodeGenerator::postvisit( NameExpr * nameExpr ) { 582 580 extension( nameExpr ); 583 OperatorInfo opInfo;584 if ( op eratorLookup( nameExpr->name, opInfo )) {585 if ( opInfo .type == OT_CONSTANT ) {586 output << opInfo .symbol;581 const OperatorInfo * opInfo = operatorLookup( nameExpr->name ); 582 if ( opInfo ) { 583 if ( opInfo->type == OT_CONSTANT ) { 584 output << opInfo->symbol; 587 585 } else { 588 output << opInfo .outputName;586 output << opInfo->outputName; 589 587 } 590 588 } else { … … 654 652 void CodeGenerator::postvisit( VariableExpr * variableExpr ) { 655 653 extension( variableExpr ); 656 OperatorInfoopInfo;657 if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && operatorLookup( variableExpr->get_var()->get_name(), opInfo ) && opInfo.type == OT_CONSTANT ) {658 output << opInfo .symbol;654 const OperatorInfo * opInfo; 655 if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && (opInfo = operatorLookup( variableExpr->get_var()->get_name() )) && opInfo->type == OT_CONSTANT ) { 656 output << opInfo->symbol; 659 657 } else { 660 658 output << mangleName( variableExpr->get_var() ); … … 1011 1009 case BranchStmt::FallThroughDefault: 1012 1010 assertf( ! options.genC, "fallthru should not reach code generation." ); 1013 1011 output << "fallthru"; 1014 1012 break; 1015 1013 } // switch … … 1035 1033 1036 1034 output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ? 1037 1035 "throw" : "throwResume"); 1038 1036 if (throwStmt->get_expr()) { 1039 1037 output << " "; … … 1050 1048 1051 1049 output << ((stmt->get_kind() == CatchStmt::Terminate) ? 1052 "catch" : "catchResume");1050 "catch" : "catchResume"); 1053 1051 output << "( "; 1054 1052 stmt->decl->accept( *visitor ); … … 1187 1185 1188 1186 std::string genName( DeclarationWithType * decl ) { 1189 CodeGen::OperatorInfo opInfo;1190 if ( op eratorLookup( decl->get_name(), opInfo )) {1191 return opInfo .outputName;1187 const OperatorInfo * opInfo = operatorLookup( decl->get_name() ); 1188 if ( opInfo ) { 1189 return opInfo->outputName; 1192 1190 } else { 1193 1191 return decl->get_name(); -
src/CodeGen/CodeGenerator.h
rbdfc032 reef8dfb 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue Apr 30 12:01:00 201913 // Update Count : 5711 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 16 03:58:31 2020 13 // Update Count : 62 14 14 // 15 15 … … 29 29 namespace CodeGen { 30 30 struct CodeGenerator : public WithShortCircuiting, public WithGuards, public WithVisitorRef<CodeGenerator> { 31 31 static int tabsize; 32 32 33 33 CodeGenerator( std::ostream &os, bool pretty = false, bool genC = false, bool lineMarks = false, bool printExprTypes = false ); … … 104 104 void postvisit( AsmStmt * ); 105 105 void postvisit( DirectiveStmt * ); 106 void postvisit( AsmDecl * ); // special: statement in declaration context106 void postvisit( AsmDecl * ); // special: statement in declaration context 107 107 void postvisit( IfStmt * ); 108 108 void postvisit( SwitchStmt * ); … … 147 147 LabelPrinter printLabels; 148 148 Options options; 149 public:149 public: 150 150 LineEnder endl; 151 private:151 private: 152 152 153 153 CodeLocation currentLocation; … … 162 162 template< class Iterator > 163 163 void CodeGenerator::genCommaList( Iterator begin, Iterator end ) { 164 164 if ( begin == end ) return; 165 165 for ( ;; ) { 166 166 (*begin++)->accept( *visitor ); 167 167 if ( begin == end ) break; 168 168 output << ", "; // separator 169 169 } // for -
src/CodeGen/FixMain.cc
rbdfc032 reef8dfb 26 26 #include "SynTree/Declaration.h" // for FunctionDecl, operator<< 27 27 #include "SynTree/Type.h" // for FunctionType 28 #include "SymTab/Mangler.h" 28 29 29 30 namespace CodeGen { … … 47 48 if( main_signature ) { 48 49 os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return "; 50 main_signature->mangleName = SymTab::Mangler::mangle(main_signature.get()); 49 51 50 52 os << main_signature->get_scopedMangleName() << "("; -
src/CodeGen/FixMain.h
rbdfc032 reef8dfb 10 10 // Created On : Thr Jan 12 14:11:09 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:12:21 201913 // Update Count : 312 // Last Modified On : Sun Feb 16 03:24:32 2020 13 // Update Count : 5 14 14 // 15 15 … … 42 42 static std::unique_ptr<FunctionDecl> main_signature; 43 43 }; 44 } ;44 } // namespace CodeGen -
src/CodeGen/FixNames.cc
rbdfc032 reef8dfb 31 31 #include "SynTree/Type.h" // for Type, BasicType, Type::Qualifiers 32 32 #include "SynTree/Visitor.h" // for Visitor, acceptAll 33 #include "CompilationState.h" 33 34 34 35 namespace CodeGen { … … 102 103 if ( dwt->get_name() != "" ) { 103 104 if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) { 104 dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) ); 105 if (!useNewAST) { 106 dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) ); 107 } 105 108 dwt->set_scopeLevel( scopeLevel ); 106 109 } // if -
src/CodeGen/GenType.h
rbdfc032 reef8dfb 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue Apr 30 11:47:00 201913 // Update Count : 311 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 16 04:11:40 2020 13 // Update Count : 5 14 14 // 15 15 … … 25 25 std::string genType( Type *type, const std::string &baseString, const Options &options ); 26 26 std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false ); 27 27 std::string genPrettyType( Type * type, const std::string & baseString ); 28 28 } // namespace CodeGen 29 29 -
src/CodeGen/Generate.cc
rbdfc032 reef8dfb 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:38:56 201913 // Update Count : 812 // Last Modified On : Sun Feb 16 03:01:51 2020 13 // Update Count : 9 14 14 // 15 15 #include "Generate.h" … … 64 64 void generate( BaseSyntaxNode * node, std::ostream & os ) { 65 65 if ( Type * type = dynamic_cast< Type * >( node ) ) { 66 os << CodeGen::genPrettyType( type, "" );66 os << genPrettyType( type, "" ); 67 67 } else { 68 68 PassVisitor<CodeGenerator> cgv( os, true, false, false, false ); -
src/CodeGen/OperatorTable.cc
rbdfc032 reef8dfb 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 15 17:12:22 201713 // Update Count : 1512 // Last Modified On : Tue Feb 18 15:55:01 2020 13 // Update Count : 55 14 14 // 15 15 … … 17 17 #include <map> // for map, _Rb_tree_const_iterator, map<>::const_iterator 18 18 #include <utility> // for pair 19 using namespace std; 19 20 20 21 #include "OperatorTable.h" … … 22 23 23 24 namespace CodeGen { 24 namespace{25 const OperatorInfo tableValues[] = {26 { "?[?]", "", "_operator_index", OT_INDEX},27 { "?{}", "=", "_constructor", OT_CTOR},28 { "^?{}", "", "_destructor", OT_DTOR},29 { "?()", "", "_operator_call", OT_CALL},30 { "?++", "++", "_operator_postincr", OT_POSTFIXASSIGN},31 { "?--", "--", "_operator_postdecr", OT_POSTFIXASSIGN},32 { "*?", "*", "_operator_deref", OT_PREFIX},33 { "+?", "+", "_operator_unaryplus", OT_PREFIX},34 { "-?", "-", "_operator_unaryminus", OT_PREFIX},35 { "~?", "~", "_operator_bitnot", OT_PREFIX},36 { "!?", "!", "_operator_lognot", OT_PREFIX},37 { "++?", "++", "_operator_preincr", OT_PREFIXASSIGN},38 { "--?", "--", "_operator_predecr", OT_PREFIXASSIGN},39 { "?\\?", "\\", "_operator_exponential", OT_INFIX},40 { "?*?", "*", "_operator_multiply", OT_INFIX},41 { "?/?", "/", "_operator_divide", OT_INFIX},42 { "?%?", "%", "_operator_modulus", OT_INFIX},43 { "?+?", "+", "_operator_add", OT_INFIX},44 { "?-?", "-", "_operator_subtract", OT_INFIX},45 { "?<<?", "<<", "_operator_shiftleft", OT_INFIX},46 { "?>>?", ">>", "_operator_shiftright", OT_INFIX},47 { "?<?", "<", "_operator_less", OT_INFIX},48 { "?>?", ">", "_operator_greater", OT_INFIX},49 { "?<=?", "<=", "_operator_lessequal", OT_INFIX},50 { "?>=?", ">=", "_operator_greaterequal", OT_INFIX},51 { "?==?", "==", "_operator_equal", OT_INFIX},52 { "?!=?", "!=", "_operator_notequal", OT_INFIX},53 { "?&?", "&", "_operator_bitand", OT_INFIX},54 { "?^?", "^", "_operator_bitxor", OT_INFIX},55 { "?|?", "|", "_operator_bitor", OT_INFIX},56 { "?=?", "=", "_operator_assign", OT_INFIXASSIGN},57 { "?\\=?", "\\=", "_operator_expassign", OT_INFIXASSIGN},58 { "?*=?", "*=", "_operator_multassign", OT_INFIXASSIGN},59 { "?/=?", "/=", "_operator_divassign", OT_INFIXASSIGN},60 { "?%=?", "%=", "_operator_modassign", OT_INFIXASSIGN},61 { "?+=?", "+=", "_operator_addassign", OT_INFIXASSIGN},62 { "?-=?", "-=", "_operator_subassign", OT_INFIXASSIGN},63 { "?<<=?", "<<=", "_operator_shiftleftassign", OT_INFIXASSIGN},64 { "?>>=?", ">>=", "_operator_shiftrightassign", OT_INFIXASSIGN},65 { "?&=?", "&=", "_operator_bitandassign", OT_INFIXASSIGN},66 { "?^=?", "^=", "_operator_bitxorassign", OT_INFIXASSIGN},67 { "?|=?", "|=", "_operator_bitorassign", OT_INFIXASSIGN},68 };25 const OperatorInfo CodeGen::tableValues[] = { 26 // inputName symbol outputName friendlyName type 27 { "?[?]", "", "_operator_index", "Index", OT_INDEX }, 28 { "?{}", "=", "_constructor", "Constructor", OT_CTOR }, 29 { "^?{}", "", "_destructor", "Destructor", OT_DTOR }, 30 { "?()", "", "_operator_call", "Call Operator", OT_CALL }, 31 { "?++", "++", "_operator_postincr", "Postfix Increment", OT_POSTFIXASSIGN }, 32 { "?--", "--", "_operator_postdecr", "Postfix Decrement", OT_POSTFIXASSIGN }, 33 { "*?", "*", "_operator_deref", "Dereference", OT_PREFIX }, 34 { "+?", "+", "_operator_unaryplus", "Plus", OT_PREFIX }, 35 { "-?", "-", "_operator_unaryminus", "Minus", OT_PREFIX }, 36 { "~?", "~", "_operator_bitnot", "Bitwise Not", OT_PREFIX }, 37 { "!?", "!", "_operator_lognot", "Logical Not", OT_PREFIX }, 38 { "++?", "++", "_operator_preincr", "Prefix Increment", OT_PREFIXASSIGN }, 39 { "--?", "--", "_operator_predecr", "Prefix Decrement", OT_PREFIXASSIGN }, 40 { "?\\?", "\\", "_operator_exponential", "Exponentiation", OT_INFIX }, 41 { "?*?", "*", "_operator_multiply", "Multiplication", OT_INFIX }, 42 { "?/?", "/", "_operator_divide", "Division", OT_INFIX }, 43 { "?%?", "%", "_operator_modulus", "Modulo", OT_INFIX }, 44 { "?+?", "+", "_operator_add", "Addition", OT_INFIX }, 45 { "?-?", "-", "_operator_subtract", "Substraction", OT_INFIX }, 46 { "?<<?", "<<", "_operator_shiftleft", "Shift Left", OT_INFIX }, 47 { "?>>?", ">>", "_operator_shiftright", "Shift Right", OT_INFIX }, 48 { "?<?", "<", "_operator_less", "Less-than", OT_INFIX }, 49 { "?>?", ">", "_operator_greater", "Greater-than", OT_INFIX }, 50 { "?<=?", "<=", "_operator_lessequal", "Less-than-or-Equal", OT_INFIX }, 51 { "?>=?", ">=", "_operator_greaterequal", "Greater-than-or-Equal", OT_INFIX }, 52 { "?==?", "==", "_operator_equal", "Equality", OT_INFIX }, 53 { "?!=?", "!=", "_operator_notequal", "Not-Equal", OT_INFIX }, 54 { "?&?", "&", "_operator_bitand", "Bitwise And", OT_INFIX }, 55 { "?^?", "^", "_operator_bitxor", "Bitwise Xor", OT_INFIX }, 56 { "?|?", "|", "_operator_bitor", "Bitwise Or", OT_INFIX }, 57 { "?=?", "=", "_operator_assign", "Assignment", OT_INFIXASSIGN }, 58 { "?\\=?", "\\=", "_operator_expassign", "Exponentiation Assignment", OT_INFIXASSIGN }, 59 { "?*=?", "*=", "_operator_multassign", "Multiplication Assignment", OT_INFIXASSIGN }, 60 { "?/=?", "/=", "_operator_divassign", "Division Assignment", OT_INFIXASSIGN }, 61 { "?%=?", "%=", "_operator_modassign", "Modulo Assignment", OT_INFIXASSIGN }, 62 { "?+=?", "+=", "_operator_addassign", "Addition Assignment", OT_INFIXASSIGN }, 63 { "?-=?", "-=", "_operator_subassign", "Substrction Assignment", OT_INFIXASSIGN }, 64 { "?<<=?", "<<=", "_operator_shiftleftassign", "Shift Left Assignment", OT_INFIXASSIGN }, 65 { "?>>=?", ">>=", "_operator_shiftrightassign", "Shift Right Assignment", OT_INFIXASSIGN }, 66 { "?&=?", "&=", "_operator_bitandassign", "Bitwise And Assignment", OT_INFIXASSIGN }, 67 { "?^=?", "^=", "_operator_bitxorassign", "Bitwise Xor Assignment", OT_INFIXASSIGN }, 68 { "?|=?", "|=", "_operator_bitorassign", "Bitwise Or Assignment", OT_INFIXASSIGN }, 69 }; // tableValues 69 70 70 const int numOps = sizeof( tableValues ) / sizeof( OperatorInfo );71 std::map< std::string, OperatorInfo > CodeGen::table; 71 72 72 std::map< std::string, OperatorInfo > table; 73 74 void initialize() { 75 for ( int i = 0; i < numOps; ++i ) { 76 table[ tableValues[i].inputName ] = tableValues[i]; 77 } // for 78 } 79 } // namespace 80 81 bool operatorLookup( const std::string & funcName, OperatorInfo & info ) { 82 static bool init = false; 83 if ( ! init ) { 84 initialize(); 85 } // if 86 87 std::map< std::string, OperatorInfo >::const_iterator i = table.find( funcName ); 88 if ( i == table.end() ) { 89 if ( isPrefix( funcName, "?`" ) ) { 90 // handle literal suffixes, which are user-defined postfix operators 91 info.inputName = funcName; 92 info.symbol = funcName.substr(2); 93 info.outputName = toString( "__operator_literal_", info.symbol ); 94 info.type = OT_POSTFIX; 95 return true; 96 } 97 return false; 98 } else { 99 info = i->second; 100 return true; 101 } // if 73 CodeGen::CodeGen() { 74 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) }; 75 for ( int i = 0; i < numOps; i += 1 ) { 76 table[ tableValues[i].inputName ] = tableValues[i]; 77 } // for 102 78 } 103 79 104 bool isOperator( const std::string & funcName ) { 105 OperatorInfo info; 106 return operatorLookup( funcName, info ); 80 const OperatorInfo * operatorLookup( const string & funcName ) { 81 if ( funcName.find_first_of( "?^*+-!", 0, 1 ) == string::npos ) return nullptr; // prefilter 82 const OperatorInfo * ret = &CodeGen::table.find( funcName )->second; // must be in the table 83 assert( ret ); 84 return ret; 107 85 } 108 86 109 /// determines if a given function name is one of the operator types between [begin, end) 110 template<typename Iterator> 111 bool isOperatorType( const std::string & funcName, Iterator begin, Iterator end ) { 112 OperatorInfo info; 113 if ( operatorLookup( funcName, info ) ) { 114 return std::find( begin, end, info.type ) != end; 115 } 87 bool isOperator( const string & funcName ) { 88 return operatorLookup( funcName ) != nullptr; 89 } 90 91 string operatorFriendlyName( const string & funcName ) { 92 const OperatorInfo * info = operatorLookup( funcName ); 93 if ( info ) return info->friendlyName; 94 return ""; 95 } 96 97 bool isConstructor( const string & funcName ) { 98 const OperatorInfo * info = operatorLookup( funcName ); 99 if ( info ) return info->type == OT_CTOR; 116 100 return false; 117 101 } 118 102 119 bool isConstructor( const std::string & funcName ) { 120 static OperatorType types[] = { OT_CTOR }; 121 return isOperatorType( funcName, std::begin(types), std::end(types) ); 103 bool isDestructor( const string & funcName ) { 104 const OperatorInfo * info = operatorLookup( funcName ); 105 if ( info ) return info->type == OT_DTOR; 106 return false; 122 107 } 123 108 124 bool isDestructor( const std::string & funcName ) { 125 static OperatorType types[] = { OT_DTOR }; 126 return isOperatorType( funcName, std::begin(types), std::end(types) ); 109 bool isCtorDtor( const string & funcName ) { 110 const OperatorInfo * info = operatorLookup( funcName ); 111 if ( info ) return info->type <= OT_CONSTRUCTOR; 112 return false; 127 113 } 128 114 129 bool isAssignment( const std::string & funcName ) { 130 static OperatorType types[] = { OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN }; 131 return isOperatorType( funcName, std::begin(types), std::end(types) ); 115 bool isAssignment( const string & funcName ) { 116 const OperatorInfo * info = operatorLookup( funcName ); 117 if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT; 118 return false; 132 119 } 133 120 134 bool isCtorDtor( const std::string & funcName ) { 135 static OperatorType types[] = { OT_CTOR, OT_DTOR }; 136 return isOperatorType( funcName, std::begin(types), std::end(types) ); 121 bool isCtorDtorAssign( const string & funcName ) { 122 const OperatorInfo * info = operatorLookup( funcName ); 123 if ( info ) return info->type <= OT_ASSIGNMENT; 124 return false; 137 125 } 138 126 139 bool isCtorDtorAssign( const std::string & funcName ) { 140 static OperatorType types[] = { OT_CTOR, OT_DTOR, OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN }; 141 return isOperatorType( funcName, std::begin(types), std::end(types) ); 142 } 127 CodeGen codegen; // initialize singleton package 143 128 } // namespace CodeGen 144 129 145 130 // Local Variables: // 146 131 // tab-width: 4 // 147 // mode: c++ //148 // compile-command: "make install" //149 132 // End: // -
src/CodeGen/OperatorTable.h
rbdfc032 reef8dfb 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 21 22:17:11 201713 // Update Count : 612 // Last Modified On : Sun Feb 16 08:13:34 2020 13 // Update Count : 26 14 14 // 15 15 … … 17 17 18 18 #include <string> 19 #include <map> 19 20 20 21 namespace CodeGen { 21 22 enum OperatorType { 22 OT_INDEX,23 23 OT_CTOR, 24 24 OT_DTOR, 25 OT_CALL, 26 OT_PREFIX, 27 OT_POSTFIX, 28 OT_INFIX, 25 OT_CONSTRUCTOR = OT_DTOR, 29 26 OT_PREFIXASSIGN, 30 27 OT_POSTFIXASSIGN, 31 28 OT_INFIXASSIGN, 29 OT_ASSIGNMENT = OT_INFIXASSIGN, 30 OT_CALL, 31 OT_PREFIX, 32 OT_INFIX, 33 OT_POSTFIX, 34 OT_INDEX, 32 35 OT_LABELADDRESS, 33 36 OT_CONSTANT … … 38 41 std::string symbol; 39 42 std::string outputName; 43 std::string friendlyName; 40 44 OperatorType type; 41 45 }; 42 46 47 class CodeGen { 48 friend const OperatorInfo * operatorLookup( const std::string & funcName ); 49 50 static const OperatorInfo tableValues[]; 51 static std::map< std::string, OperatorInfo > table; 52 public: 53 CodeGen(); 54 }; // CodeGen 55 43 56 bool isOperator( const std::string & funcName ); 44 bool operatorLookup( const std::string & funcName, OperatorInfo & info ); 57 const OperatorInfo * operatorLookup( const std::string & funcName ); 58 std::string operatorFriendlyName( const std::string & funcName ); 45 59 46 60 bool isConstructor( const std::string & ); -
src/CodeGen/Options.h
rbdfc032 reef8dfb 9 9 // Author : Andrew Beach 10 10 // Created On : Tue Apr 30 11:36:00 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thr May 2 10:45:00 201913 // Update Count : 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 15 18:37:06 2020 13 // Update Count : 3 14 14 // 15 15 16 16 #pragma once 17 17 18 namespace CodeGen { 19 struct Options { 20 // External Options: Same thoughout a pass. 21 bool pretty; 22 bool genC; 23 bool lineMarks; 24 bool printExprTypes; 18 struct Options { 19 // External Options: Same thoughout a pass. 20 bool pretty; 21 bool genC; 22 bool lineMarks; 23 bool printExprTypes; 25 24 26 27 25 // Internal Options: Changed on some recurisive calls. 26 bool anonymousUnused = false; 28 27 29 30 28 Options(bool pretty, bool genC, bool lineMarks, bool printExprTypes) : 29 pretty(pretty), genC(genC), lineMarks(lineMarks), printExprTypes(printExprTypes) 31 30 {} 32 }; 33 } // namespace CodeGen 31 }; 34 32 35 33 // Local Variables: // -
src/CodeGen/module.mk
rbdfc032 reef8dfb 20 20 SRC_CODEGEN = \ 21 21 CodeGen/CodeGenerator.cc \ 22 CodeGen/CodeGenerator.h \ 22 23 CodeGen/FixMain.cc \ 24 CodeGen/FixMain.h \ 23 25 CodeGen/GenType.cc \ 24 CodeGen/OperatorTable.cc 26 CodeGen/GenType.h \ 27 CodeGen/OperatorTable.cc \ 28 CodeGen/OperatorTable.h \ 29 CodeGen/Options.h 25 30 26 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/ FixNames.cc31 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/Generate.h CodeGen/FixNames.cc CodeGen/FixNames.h 27 32 SRCDEMANGLE += $(SRC_CODEGEN) -
src/CodeTools/ResolvProtoDump.cc
rbdfc032 reef8dfb 9 9 // Author : Aaron Moss 10 10 // Created On : Tue Sep 11 09:04:00 2018 11 // Last Modified By : Aaron Moss12 // Last Modified On : Tue Sep 11 09:04:00 201813 // Update Count : 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 15 13:50:11 2020 13 // Update Count : 3 14 14 // 15 15 … … 182 182 183 183 // replace operator names 184 CodeGen::OperatorInfo info;185 if ( CodeGen::operatorLookup( name, info )) {184 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( name ); 185 if ( opInfo ) { 186 186 ss << new_prefix(pre, ""); 187 op_name( info.outputName, ss );187 op_name( opInfo->outputName, ss ); 188 188 return; 189 189 } -
src/CodeTools/TrackLoc.cc
rbdfc032 reef8dfb 10 10 // Created On : Tues May 2 15:46:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed May 3 14:43:00 201713 // Update Count : 012 // Last Modified On : Fri Nov 27 18:00:00 2020 13 // Update Count : 1 14 14 // 15 15 … … 22 22 #include <string> // for operator<<, string 23 23 #include <typeindex> // for type_index 24 #include <vector> // for vector 24 25 25 26 #include "Common/PassVisitor.h" // for PassVisitor … … 37 38 CodeLocation *lastNode; 38 39 39 std::stack< CodeLocation * > parents;40 std::stack< CodeLocation *, std::vector< CodeLocation * > > parents; 40 41 public: 41 42 LocationPrinter(size_t printLevel) : -
src/CodeTools/module.mk
rbdfc032 reef8dfb 15 15 ############################################################################### 16 16 17 SRC += CodeTools/DeclStats.cc \ 17 SRC += \ 18 CodeTools/DeclStats.cc \ 19 CodeTools/DeclStats.h \ 18 20 CodeTools/ResolvProtoDump.cc \ 19 CodeTools/TrackLoc.cc 21 CodeTools/ResolvProtoDump.h \ 22 CodeTools/TrackLoc.cc \ 23 CodeTools/TrackLoc.h -
src/Common/CodeLocation.h
rbdfc032 reef8dfb 42 42 } 43 43 44 bool followedBy( CodeLocation const & other, int seperation ) { 44 bool startsBefore( CodeLocation const & other ) const { 45 if( filename < other.filename ) return true; 46 if( filename > other.filename ) return false; 47 48 if( first_line < other.first_line ) return true; 49 if( first_line > other.first_line ) return false; 50 51 if( last_line < other.last_line ) return true; 52 return false; 53 } 54 55 bool followedBy( CodeLocation const & other, int seperation ) const { 45 56 return (first_line + seperation == other.first_line && 46 57 filename == other.filename); 47 58 } 48 59 49 bool operator==( CodeLocation const & other ) {60 bool operator==( CodeLocation const & other ) const { 50 61 return followedBy( other, 0 ); 51 62 } 52 63 53 bool operator!=( CodeLocation const & other ) {64 bool operator!=( CodeLocation const & other ) const { 54 65 return !(*this == other); 55 66 } -
src/Common/Eval.cc
rbdfc032 reef8dfb 168 168 if (expr) { 169 169 expr->accept(ev); 170 return std::make_pair(ev. pass.value, ev.pass.valid);170 return std::make_pair(ev.core.value, ev.core.valid); 171 171 } else { 172 172 return std::make_pair(0, false); -
src/Common/PassVisitor.h
rbdfc032 reef8dfb 110 110 virtual void visit( FinallyStmt * finallyStmt ) override final; 111 111 virtual void visit( const FinallyStmt * finallyStmt ) override final; 112 virtual void visit( SuspendStmt * suspendStmt ) override final; 113 virtual void visit( const SuspendStmt * suspendStmt ) override final; 112 114 virtual void visit( WaitForStmt * waitforStmt ) override final; 113 115 virtual void visit( const WaitForStmt * waitforStmt ) override final; … … 276 278 virtual Statement * mutate( CatchStmt * catchStmt ) override final; 277 279 virtual Statement * mutate( FinallyStmt * finallyStmt ) override final; 280 virtual Statement * mutate( SuspendStmt * suspendStmt ) override final; 278 281 virtual Statement * mutate( WaitForStmt * waitforStmt ) override final; 279 282 virtual Declaration * mutate( WithStmt * withStmt ) override final; … … 351 354 virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final; 352 355 356 bool isInFunction() const { 357 return inFunction; 358 } 359 353 360 private: 354 361 bool inFunction = false; 362 bool atFunctionTop = false; 355 363 356 364 template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor ); … … 523 531 public: 524 532 PassVisitor<pass_type> * const visitor = nullptr; 533 534 bool isInFunction() const { 535 return visitor->isInFunction(); 536 } 525 537 }; 526 538 -
src/Common/PassVisitor.impl.h
rbdfc032 reef8dfb 532 532 indexerAddId( &func ); 533 533 maybeAccept_impl( node->type, *this ); 534 // function body needs to have the same scope as parameters - CompoundStmt will not enter 535 // a new scope if inFunction is true 534 // First remember that we are now within a function. 536 535 ValueGuard< bool > oldInFunction( inFunction ); 537 536 inFunction = true; 537 // The function body needs to have the same scope as parameters. 538 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 539 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 540 atFunctionTop = true; 538 541 maybeAccept_impl( node->statements, *this ); 539 542 maybeAccept_impl( node->attributes, *this ); … … 567 570 indexerAddId( &func ); 568 571 maybeAccept_impl( node->type, *this ); 569 // function body needs to have the same scope as parameters - CompoundStmt will not enter 570 // a new scope if inFunction is true 572 // First remember that we are now within a function. 571 573 ValueGuard< bool > oldInFunction( inFunction ); 572 574 inFunction = true; 575 // The function body needs to have the same scope as parameters. 576 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 577 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 578 atFunctionTop = true; 573 579 maybeAccept_impl( node->statements, *this ); 574 580 maybeAccept_impl( node->attributes, *this ); … … 601 607 indexerAddId( &func ); 602 608 maybeMutate_impl( node->type, *this ); 603 // function body needs to have the same scope as parameters - CompoundStmt will not enter 604 // a new scope if inFunction is true 609 // First remember that we are now within a function. 605 610 ValueGuard< bool > oldInFunction( inFunction ); 606 611 inFunction = true; 612 // The function body needs to have the same scope as parameters. 613 // A CompoundStmt will not enter a new scope if atFunctionTop is true. 614 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 615 atFunctionTop = true; 607 616 maybeMutate_impl( node->statements, *this ); 608 617 maybeMutate_impl( node->attributes, *this ); … … 826 835 { 827 836 auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 828 maybeAccept_impl( node->parameters, *this );829 837 maybeAccept_impl( node->base , *this ); 830 838 } … … 849 857 { 850 858 auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 851 maybeAccept_impl( node->parameters, *this );852 859 maybeAccept_impl( node->base , *this ); 853 860 } … … 871 878 { 872 879 auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 873 maybeMutate_impl( node->parameters, *this );874 880 maybeMutate_impl( node->base , *this ); 875 881 } … … 895 901 { 896 902 auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 897 maybeAccept_impl( node->parameters, *this );898 903 maybeAccept_impl( node->base , *this ); 899 904 } … … 912 917 { 913 918 auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 914 maybeAccept_impl( node->parameters, *this );915 919 maybeAccept_impl( node->base , *this ); 916 920 } … … 929 933 { 930 934 auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } ); 931 maybeMutate_impl( node->parameters, *this );932 935 maybeMutate_impl( node->base , *this ); 933 936 } … … 1007 1010 VISIT_START( node ); 1008 1011 { 1009 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1010 ValueGuard< bool > old InFunction( inFunction);1011 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1012 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1013 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1014 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1012 1015 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1013 inFunction= false;1016 atFunctionTop = false; 1014 1017 visitStatementList( node->kids ); 1015 1018 } … … 1021 1024 VISIT_START( node ); 1022 1025 { 1023 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1024 ValueGuard< bool > old InFunction( inFunction);1025 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1026 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1027 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1028 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1026 1029 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1027 inFunction= false;1030 atFunctionTop = false; 1028 1031 visitStatementList( node->kids ); 1029 1032 } … … 1035 1038 MUTATE_START( node ); 1036 1039 { 1037 // do not enter a new scope if inFunction is true - needs to check old state before the assignment1038 ValueGuard< bool > old InFunction( inFunction);1039 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old) indexerScopeLeave(); } );1040 // Do not enter a new scope if atFunctionTop is true, don't leave one either. 1041 ValueGuard< bool > oldAtFunctionTop( atFunctionTop ); 1042 auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } ); 1040 1043 auto guard2 = makeFuncGuard( [this]() { call_beginScope(); }, [this]() { call_endScope(); } ); 1041 inFunction= false;1044 atFunctionTop = false; 1042 1045 mutateStatementList( node->kids ); 1043 1046 } … … 1522 1525 1523 1526 //-------------------------------------------------------------------------- 1527 // SuspendStmt 1528 template< typename pass_type > 1529 void PassVisitor< pass_type >::visit( SuspendStmt * node ) { 1530 VISIT_START( node ); 1531 1532 maybeAccept_impl( node->then , *this ); 1533 1534 VISIT_END( node ); 1535 } 1536 1537 template< typename pass_type > 1538 void PassVisitor< pass_type >::visit( const SuspendStmt * node ) { 1539 VISIT_START( node ); 1540 1541 maybeAccept_impl( node->then , *this ); 1542 1543 VISIT_END( node ); 1544 } 1545 1546 template< typename pass_type > 1547 Statement * PassVisitor< pass_type >::mutate( SuspendStmt * node ) { 1548 MUTATE_START( node ); 1549 1550 maybeMutate_impl( node->then , *this ); 1551 1552 MUTATE_END( Statement, node ); 1553 } 1554 1555 //-------------------------------------------------------------------------- 1524 1556 // WaitForStmt 1525 1557 template< typename pass_type > … … 3302 3334 VISIT_START( node ); 3303 3335 3304 indexerAdd Struct( node->name );3336 indexerAddUnion( node->name ); 3305 3337 3306 3338 { … … 3317 3349 VISIT_START( node ); 3318 3350 3319 indexerAdd Struct( node->name );3351 indexerAddUnion( node->name ); 3320 3352 3321 3353 { … … 3332 3364 MUTATE_START( node ); 3333 3365 3334 indexerAdd Struct( node->name );3366 indexerAddUnion( node->name ); 3335 3367 3336 3368 { -
src/Common/PassVisitor.proto.h
rbdfc032 reef8dfb 38 38 }; 39 39 40 std::stack< cleanup_t > cleanups;40 std::stack< cleanup_t, std::vector< cleanup_t > > cleanups; 41 41 }; 42 42 -
src/Common/ScopedMap.h
rbdfc032 reef8dfb 93 93 94 94 reference operator* () { return *it; } 95 pointer operator-> () { return it.operator->(); }95 pointer operator-> () const { return it.operator->(); } 96 96 97 97 iterator& operator++ () { … … 249 249 250 250 /// Gets the note at the given scope 251 Note& getNote() { return scopes.back().note; } 252 const Note& getNote() const { return scopes.back().note; } 251 253 Note& getNote( size_type i ) { return scopes[i].note; } 252 254 const Note& getNote( size_type i ) const { return scopes[i].note; } -
src/Common/SemanticError.cc
rbdfc032 reef8dfb 90 90 void SemanticErrorException::print() { 91 91 using std::to_string; 92 93 errors.sort([](const error & lhs, const error & rhs) -> bool { 94 if(lhs.location.startsBefore(rhs.location)) return true; 95 if(rhs.location.startsBefore(lhs.location)) return false; 96 97 return lhs.description < rhs.description; 98 }); 99 92 100 for( auto err : errors ) { 93 101 std::cerr << ErrorHelpers::bold() << err.location << ErrorHelpers::error_str() << ErrorHelpers::reset_font() << err.description << std::endl; -
src/Common/SemanticError.h
rbdfc032 reef8dfb 49 49 struct WarningData { 50 50 const char * const name; 51 const Severity default_severity; 51 52 const char * const message; 52 const Severity default_severity;53 53 }; 54 54 55 55 constexpr WarningData WarningFormats[] = { 56 {"self-assign" , "self assignment of expression: %s" , Severity::Warn}, 57 {"reference-conversion" , "rvalue to reference conversion of rvalue: %s" , Severity::Warn}, 58 {"qualifiers-zero_t-one_t", "questionable use of type qualifier %s with %s", Severity::Warn}, 59 {"aggregate-forward-decl" , "forward declaration of nested aggregate: %s" , Severity::Warn}, 60 {"superfluous-decl" , "declaration does not allocate storage: %s" , Severity::Warn}, 61 {"gcc-attributes" , "invalid attribute: %s" , Severity::Warn}, 56 {"self-assign" , Severity::Warn , "self assignment of expression: %s" }, 57 {"reference-conversion" , Severity::Warn , "rvalue to reference conversion of rvalue: %s" }, 58 {"qualifiers-zero_t-one_t", Severity::Warn , "questionable use of type qualifier %s with %s" }, 59 {"aggregate-forward-decl" , Severity::Warn , "forward declaration of nested aggregate: %s" }, 60 {"superfluous-decl" , Severity::Warn , "declaration does not allocate storage: %s" }, 61 {"gcc-attributes" , Severity::Warn , "invalid attribute: %s" }, 62 {"c++-like-copy" , Severity::Warn , "Constructor from reference is not a valid copy constructor" }, 62 63 }; 63 64 … … 69 70 SuperfluousDecl, 70 71 GccAttributes, 72 CppCopy, 71 73 NUMBER_OF_WARNINGS, // This MUST be the last warning 72 74 }; -
src/Common/Stats/Heap.cc
rbdfc032 reef8dfb 53 53 const size_t passes_size = sizeof(passes) / sizeof(passes[0]); 54 54 size_t passes_cnt = 1; 55 56 StatBlock stacktrace_stats[100]; 57 size_t stacktrace_stats_count = 0; 58 bool stacktrace_stats_enabled = true; 59 60 size_t trace[1000]; 61 const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t); 62 size_t stacktrace_depth; 63 64 size_t new_stacktrace_id(const char * const name) { 65 stacktrace_stats[stacktrace_stats_count].name = name; 66 return stacktrace_stats_count++; 67 } 68 69 void stacktrace_push(size_t id) { 70 ++stacktrace_depth; 71 assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc"); 72 trace[stacktrace_depth] = id; 73 } 74 75 void stacktrace_pop() { 76 assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty"); 77 --stacktrace_depth; 78 } 55 79 56 80 void newPass( const char * const name ) { … … 116 140 for(size_t i = 0; i < passes_cnt; i++) { 117 141 print(passes[i], nc, total_mallocs, total_frees, overall_peak); 142 } 143 144 print('-', nct); 145 std::cerr << std::setw(nc) << "Trace"; 146 std::cerr << " | Malloc Count | Free Count | Peak Allocs |" << std::endl; 147 148 print('-', nct); 149 for (size_t i = 0; i < stacktrace_stats_count; i++) { 150 print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak); 118 151 } 119 152 print('-', nct); … … 188 221 = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs); 189 222 } 223 224 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 225 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 226 } 190 227 return __malloc( size ); 191 228 } … … 196 233 passes[passes_cnt - 1].frees++; 197 234 passes[passes_cnt - 1].n_allocs--; 235 } 236 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 237 stacktrace_stats[trace[stacktrace_depth]].frees++; 198 238 } 199 239 return __free( ptr ); … … 208 248 = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs); 209 249 } 250 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 251 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 252 } 210 253 return __calloc( nelem, size ); 211 254 } … … 218 261 passes[passes_cnt - 1].frees++; 219 262 } // if 263 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 264 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 265 stacktrace_stats[trace[stacktrace_depth]].frees++; 266 } 220 267 return s; 221 268 } -
src/Common/Stats/Heap.h
rbdfc032 reef8dfb 20 20 void newPass( const char * const name ); 21 21 void print(); 22 23 size_t new_stacktrace_id(const char * const name); 24 void stacktrace_push(size_t id); 25 void stacktrace_pop(); 22 26 } 23 27 } -
src/Common/Stats/Stats.cc
rbdfc032 reef8dfb 35 35 } 36 36 37 namespace ResolveTime { 38 bool enabled = false; 39 } 40 37 41 struct { 38 42 const char * const opt; … … 43 47 { "heap" , Heap::enabled }, 44 48 { "time" , Time::enabled }, 49 { "resolve" , ResolveTime::enabled }, 45 50 }; 46 51 -
src/Common/module.mk
rbdfc032 reef8dfb 17 17 SRC_COMMON = \ 18 18 Common/Assert.cc \ 19 Common/CodeLocation.h \ 20 Common/CodeLocationTools.hpp \ 21 Common/CodeLocationTools.cpp \ 22 Common/CompilerError.h \ 23 Common/Debug.h \ 24 Common/ErrorObjects.h \ 19 25 Common/Eval.cc \ 26 Common/Examine.cc \ 27 Common/Examine.h \ 28 Common/FilterCombos.h \ 29 Common/Indenter.h \ 20 30 Common/PassVisitor.cc \ 31 Common/PassVisitor.h \ 32 Common/PassVisitor.impl.h \ 33 Common/PassVisitor.proto.h \ 34 Common/PersistentMap.h \ 35 Common/ScopedMap.h \ 21 36 Common/SemanticError.cc \ 37 Common/SemanticError.h \ 38 Common/Stats.h \ 39 Common/Stats/Base.h \ 22 40 Common/Stats/Counter.cc \ 41 Common/Stats/Counter.h \ 23 42 Common/Stats/Heap.cc \ 43 Common/Stats/Heap.h \ 44 Common/Stats/ResolveTime.cc \ 45 Common/Stats/ResolveTime.h \ 24 46 Common/Stats/Stats.cc \ 25 47 Common/Stats/Time.cc \ 26 Common/UniqueName.cc 48 Common/Stats/Time.h \ 49 Common/UnimplementedError.h \ 50 Common/UniqueName.cc \ 51 Common/UniqueName.h \ 52 Common/utility.h \ 53 Common/VectorMap.h 27 54 28 55 SRC += $(SRC_COMMON) Common/DebugMalloc.cc -
src/Common/utility.h
rbdfc032 reef8dfb 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jul 24 14:28:19 201913 // Update Count : 4112 // Last Modified On : Tue Feb 11 13:00:36 2020 13 // Update Count : 50 14 14 // 15 15 … … 29 29 #include <utility> 30 30 #include <vector> 31 #include <cstring> // memcmp 31 32 32 33 #include "Common/Indenter.h" … … 264 265 } 265 266 266 // / determines if `pref` is a prefix of `str`267 static inline bool isPrefix( const std::string & str, const std::string & pref ) {267 // determines if pref is a prefix of str 268 static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) { 268 269 if ( pref.size() > str.size() ) return false; 269 auto its = std::mismatch( pref.begin(), pref.end(), str.begin() );270 return its.first == pref.end();270 return 0 == memcmp( str.c_str() + start, pref.c_str(), pref.size() ); 271 // return prefix == full.substr(0, prefix.size()); // for future, requires c++17 271 272 } 272 273 … … 359 360 reverse_iterate_t( T & ref ) : ref(ref) {} 360 361 361 typedef typename T::reverse_iterator iterator; 362 iterator begin() { return ref.rbegin(); } 363 iterator end() { return ref.rend(); } 362 // this does NOT work on const T!!! 363 // typedef typename T::reverse_iterator iterator; 364 auto begin() { return ref.rbegin(); } 365 auto end() { return ref.rend(); } 364 366 }; 365 367 -
src/CompilationState.cc
rbdfc032 reef8dfb 14 14 // 15 15 16 #include "config.h" 17 16 18 int 17 19 astp = false, … … 27 29 nopreludep = false, 28 30 genproto = false, 31 deterministic_output = false, 32 useNewAST = CFA_USE_NEW_AST, 29 33 nomainp = false, 30 34 parsep = false, -
src/CompilationState.h
rbdfc032 reef8dfb 28 28 nopreludep, 29 29 genproto, 30 deterministic_output, 31 useNewAST, 30 32 nomainp, 31 33 parsep, -
src/Concurrency/Keywords.cc
rbdfc032 reef8dfb 16 16 #include "Concurrency/Keywords.h" 17 17 18 #include <cassert> // for assert 19 #include <string> // for string, operator== 20 21 #include "Common/PassVisitor.h" // for PassVisitor 22 #include "Common/SemanticError.h" // for SemanticError 23 #include "Common/utility.h" // for deleteAll, map_range 24 #include "CodeGen/OperatorTable.h" // for isConstructor 25 #include "InitTweak/InitTweak.h" // for getPointerBase 26 #include "SynTree/LinkageSpec.h" // for Cforall 27 #include "SynTree/Constant.h" // for Constant 28 #include "SynTree/Declaration.h" // for StructDecl, FunctionDecl, ObjectDecl 29 #include "SynTree/Expression.h" // for VariableExpr, ConstantExpr, Untype... 30 #include "SynTree/Initializer.h" // for SingleInit, ListInit, Initializer ... 31 #include "SynTree/Label.h" // for Label 32 #include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt 33 #include "SynTree/Type.h" // for StructInstType, Type, PointerType 34 #include "SynTree/Visitor.h" // for Visitor, acceptAll 18 #include <cassert> // for assert 19 #include <string> // for string, operator== 20 21 #include <iostream> 22 23 #include "Common/Examine.h" // for isMainFor 24 #include "Common/PassVisitor.h" // for PassVisitor 25 #include "Common/SemanticError.h" // for SemanticError 26 #include "Common/utility.h" // for deleteAll, map_range 27 #include "CodeGen/OperatorTable.h" // for isConstructor 28 #include "ControlStruct/LabelGenerator.h" // for LebelGenerator 29 #include "InitTweak/InitTweak.h" // for getPointerBase 30 #include "SynTree/LinkageSpec.h" // for Cforall 31 #include "SynTree/Constant.h" // for Constant 32 #include "SynTree/Declaration.h" // for StructDecl, FunctionDecl, ObjectDecl 33 #include "SynTree/Expression.h" // for VariableExpr, ConstantExpr, Untype... 34 #include "SynTree/Initializer.h" // for SingleInit, ListInit, Initializer ... 35 #include "SynTree/Label.h" // for Label 36 #include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt 37 #include "SynTree/Type.h" // for StructInstType, Type, PointerType 38 #include "SynTree/Visitor.h" // for Visitor, acceptAll 39 #include "Virtual/Tables.h" 35 40 36 41 class Attribute; 37 42 38 43 namespace Concurrency { 44 inline static std::string getVTableName( std::string const & exception_name ) { 45 return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name); 46 } 47 48 // Only detects threads constructed with the keyword thread. 49 inline static bool isThread( DeclarationWithType * decl ) { 50 Type * baseType = decl->get_type()->stripDeclarator(); 51 StructInstType * instType = dynamic_cast<StructInstType *>( baseType ); 52 if ( nullptr == instType ) { return false; } 53 return instType->baseStruct->is_thread(); 54 } 55 39 56 //============================================================================================= 40 57 // Pass declarations … … 53 70 public: 54 71 55 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) : 56 type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {} 72 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, 73 std::string&& getter_name, std::string&& context_error, std::string&& exception_name, 74 bool needs_main, AggregateDecl::Aggregate cast_target ) : 75 type_name( type_name ), field_name( field_name ), getter_name( getter_name ), 76 context_error( context_error ), exception_name( exception_name ), 77 vtable_name( getVTableName( exception_name ) ), 78 needs_main( needs_main ), cast_target( cast_target ) {} 57 79 58 80 virtual ~ConcurrentSueKeyword() {} … … 62 84 63 85 void handle( StructDecl * ); 86 void addVtableForward( StructDecl * ); 64 87 FunctionDecl * forwardDeclare( StructDecl * ); 65 88 ObjectDecl * addField( StructDecl * ); … … 75 98 const std::string getter_name; 76 99 const std::string context_error; 100 const std::string exception_name; 101 const std::string vtable_name; 77 102 bool needs_main; 78 103 AggregateDecl::Aggregate cast_target; … … 80 105 StructDecl * type_decl = nullptr; 81 106 FunctionDecl * dtor_decl = nullptr; 107 StructDecl * except_decl = nullptr; 108 StructDecl * vtable_decl = nullptr; 82 109 }; 83 110 … … 88 115 // int data; int data; 89 116 // a_struct_t more_data; a_struct_t more_data; 90 // => thread_desc__thrd_d;117 // => $thread __thrd_d; 91 118 // }; }; 92 // static inline thread_desc* get_thread( MyThread * this ) { return &this->__thrd_d; }119 // static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; } 93 120 // 94 121 class ThreadKeyword final : public ConcurrentSueKeyword { … … 96 123 97 124 ThreadKeyword() : ConcurrentSueKeyword( 98 " thread_desc",125 "$thread", 99 126 "__thrd", 100 127 "get_thread", 101 128 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n", 129 "ThreadCancelled", 102 130 true, 103 131 AggregateDecl::Thread … … 120 148 // int data; int data; 121 149 // a_struct_t more_data; a_struct_t more_data; 122 // => coroutine_desc__cor_d;150 // => $coroutine __cor_d; 123 151 // }; }; 124 // static inline coroutine_desc* get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }152 // static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; } 125 153 // 126 154 class CoroutineKeyword final : public ConcurrentSueKeyword { … … 128 156 129 157 CoroutineKeyword() : ConcurrentSueKeyword( 130 " coroutine_desc",158 "$coroutine", 131 159 "__cor", 132 160 "get_coroutine", 133 161 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n", 162 "CoroutineCancelled", 134 163 true, 135 164 AggregateDecl::Coroutine … … 146 175 } 147 176 }; 177 178 148 179 149 180 //----------------------------------------------------------------------------- … … 152 183 // int data; int data; 153 184 // a_struct_t more_data; a_struct_t more_data; 154 // => monitor_desc__mon_d;185 // => $monitor __mon_d; 155 186 // }; }; 156 // static inline monitor_desc* get_coroutine( MyMonitor * this ) { return &this->__cor_d; }187 // static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; } 157 188 // 158 189 class MonitorKeyword final : public ConcurrentSueKeyword { … … 160 191 161 192 MonitorKeyword() : ConcurrentSueKeyword( 162 " monitor_desc",193 "$monitor", 163 194 "__mon", 164 195 "get_monitor", 165 196 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n", 197 "", 166 198 false, 167 199 AggregateDecl::Monitor … … 180 212 181 213 //----------------------------------------------------------------------------- 214 //Handles generator type declarations : 215 // generator MyGenerator { struct MyGenerator { 216 // int data; int data; 217 // a_struct_t more_data; a_struct_t more_data; 218 // => int __gen_next; 219 // }; }; 220 // 221 class GeneratorKeyword final : public ConcurrentSueKeyword { 222 public: 223 224 GeneratorKeyword() : ConcurrentSueKeyword( 225 "$generator", 226 "__generator_state", 227 "get_generator", 228 "Unable to find builtin type $generator\n", 229 "", 230 true, 231 AggregateDecl::Generator 232 ) 233 {} 234 235 virtual ~GeneratorKeyword() {} 236 237 virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); } 238 239 static void implement( std::list< Declaration * > & translationUnit ) { 240 PassVisitor< GeneratorKeyword > impl; 241 mutateAll( translationUnit, impl ); 242 } 243 }; 244 245 246 //----------------------------------------------------------------------------- 247 class SuspendKeyword final : public WithStmtsToAdd, public WithGuards { 248 public: 249 SuspendKeyword() = default; 250 virtual ~SuspendKeyword() = default; 251 252 void premutate( FunctionDecl * ); 253 DeclarationWithType * postmutate( FunctionDecl * ); 254 255 Statement * postmutate( SuspendStmt * ); 256 257 static void implement( std::list< Declaration * > & translationUnit ) { 258 PassVisitor< SuspendKeyword > impl; 259 mutateAll( translationUnit, impl ); 260 } 261 262 private: 263 bool is_real_suspend( FunctionDecl * ); 264 265 Statement * make_generator_suspend( SuspendStmt * ); 266 Statement * make_coroutine_suspend( SuspendStmt * ); 267 268 struct LabelPair { 269 Label obj; 270 int idx; 271 }; 272 273 LabelPair make_label() { 274 labels.push_back( gen.newLabel("generator") ); 275 return { labels.back(), int(labels.size()) }; 276 } 277 278 DeclarationWithType * in_generator = nullptr; 279 FunctionDecl * decl_suspend = nullptr; 280 std::vector<Label> labels; 281 ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator(); 282 }; 283 284 //----------------------------------------------------------------------------- 182 285 //Handles mutex routines definitions : 183 286 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) { 184 // monitor_desc* __monitors[] = { get_monitor(a), get_monitor(b) };287 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) }; 185 288 // monitor_guard_t __guard = { __monitors, 2 }; 186 289 // /*Some code*/ => /*Some code*/ … … 195 298 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first ); 196 299 void validate( DeclarationWithType * ); 197 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 198 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 300 void addDtorStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 301 void addStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &); 302 void addThreadDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ); 199 303 200 304 static void implement( std::list< Declaration * > & translationUnit ) { … … 207 311 StructDecl* guard_decl = nullptr; 208 312 StructDecl* dtor_guard_decl = nullptr; 313 StructDecl* thread_guard_decl = nullptr; 209 314 210 315 static std::unique_ptr< Type > generic_func; … … 221 326 //Handles mutex routines definitions : 222 327 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) { 223 // monitor_desc* __monitors[] = { get_monitor(a), get_monitor(b) };328 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) }; 224 329 // monitor_guard_t __guard = { __monitors, 2 }; 225 330 // /*Some code*/ => /*Some code*/ … … 251 356 CoroutineKeyword ::implement( translationUnit ); 252 357 MonitorKeyword ::implement( translationUnit ); 358 GeneratorKeyword ::implement( translationUnit ); 359 SuspendKeyword ::implement( translationUnit ); 253 360 } 254 361 … … 283 390 handle( decl ); 284 391 } 392 else if ( !except_decl && exception_name == decl->name && decl->body ) { 393 except_decl = decl; 394 } 395 else if ( !vtable_decl && vtable_name == decl->name && decl->body ) { 396 vtable_decl = decl; 397 } 398 // Might be able to get ride of is target. 399 assert( is_target(decl) == (cast_target == decl->kind) ); 285 400 return decl; 286 401 } 287 402 288 403 DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) { 289 if( !type_decl ) return decl; 290 if( !CodeGen::isDestructor( decl->name ) ) return decl; 291 292 auto params = decl->type->parameters; 293 if( params.size() != 1 ) return decl; 294 295 auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() ); 296 if( !type ) return decl; 297 298 auto stype = dynamic_cast<StructInstType*>( type->base ); 299 if( !stype ) return decl; 300 if( stype->baseStruct != type_decl ) return decl; 301 302 if( !dtor_decl ) dtor_decl = decl; 404 if ( type_decl && isDestructorFor( decl, type_decl ) ) 405 dtor_decl = decl; 406 else if ( vtable_name.empty() ) 407 ; 408 else if( !decl->has_body() ) 409 ; 410 else if ( auto param = isMainFor( decl, cast_target ) ) { 411 // This should never trigger. 412 assert( vtable_decl ); 413 // Should be safe because of isMainFor. 414 StructInstType * struct_type = static_cast<StructInstType *>( 415 static_cast<ReferenceType *>( param->get_type() )->base ); 416 assert( struct_type ); 417 418 std::list< Expression * > poly_args = { new TypeExpr( struct_type->clone() ) }; 419 ObjectDecl * vtable_object = Virtual::makeVtableInstance( 420 vtable_decl->makeInst( poly_args ), struct_type, nullptr ); 421 declsToAddAfter.push_back( vtable_object ); 422 declsToAddAfter.push_back( Virtual::makeGetExceptionFunction( 423 vtable_object, except_decl->makeInst( std::move( poly_args ) ) 424 ) ); 425 } 426 303 427 return decl; 304 428 } … … 306 430 Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) { 307 431 if ( cast_target == cast->target ) { 308 // convert (thread &)t to ( thread_desc&)*get_thread(t), etc.432 // convert (thread &)t to ($thread &)*get_thread(t), etc. 309 433 if( !type_decl ) SemanticError( cast, context_error ); 310 434 if( !dtor_decl ) SemanticError( cast, context_error ); … … 324 448 if( !dtor_decl ) SemanticError( decl, context_error ); 325 449 450 addVtableForward( decl ); 326 451 FunctionDecl * func = forwardDeclare( decl ); 327 452 ObjectDecl * field = addField( decl ); 328 453 addRoutines( field, func ); 454 } 455 456 void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) { 457 if ( vtable_decl ) { 458 std::list< Expression * > poly_args = { 459 new TypeExpr( new StructInstType( noQualifiers, decl ) ), 460 }; 461 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 462 vtable_decl->makeInst( poly_args ), 463 except_decl->makeInst( poly_args ) 464 ) ); 465 declsToAddBefore.push_back( Virtual::makeVtableForward( 466 vtable_decl->makeInst( move( poly_args ) ) ) ); 467 // Its only an error if we want a vtable and don't have one. 468 } else if ( ! vtable_name.empty() ) { 469 SemanticError( decl, context_error ); 470 } 329 471 } 330 472 … … 377 519 get_type, 378 520 nullptr, 379 noAttributes,521 { new Attribute("const") }, 380 522 Type::Inline 381 523 ); … … 434 576 new CastExpr( 435 577 new VariableExpr( func->get_functionType()->get_parameters().front() ), 436 func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone() 578 func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone(), 579 false 437 580 ) 438 581 ) … … 446 589 447 590 declsToAddAfter.push_back( get_decl ); 448 449 // get_decl->fixUniqueId(); 450 } 591 } 592 593 //============================================================================================= 594 // Suspend keyword implementation 595 //============================================================================================= 596 bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) { 597 if(isMangled(func->linkage)) return false; // the real suspend isn't mangled 598 if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name 599 if(func->type->parameters.size() != 0) return false; // Too many parameters 600 if(func->type->returnVals.size() != 0) return false; // Too many return values 601 602 return true; 603 } 604 605 void SuspendKeyword::premutate( FunctionDecl * func ) { 606 GuardValue(in_generator); 607 in_generator = nullptr; 608 609 // Is this the real suspend? 610 if(is_real_suspend(func)) { 611 decl_suspend = decl_suspend ? decl_suspend : func; 612 return; 613 } 614 615 // Is this the main of a generator? 616 auto param = isMainFor( func, AggregateDecl::Aggregate::Generator ); 617 if(!param) return; 618 619 if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void"); 620 621 in_generator = param; 622 GuardValue(labels); 623 labels.clear(); 624 } 625 626 DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) { 627 if( !func->statements ) return func; // Not the actual definition, don't do anything 628 if( !in_generator ) return func; // Not in a generator, don't do anything 629 if( labels.empty() ) return func; // Generator has no states, nothing to do, could throw a warning 630 631 // This is a generator main, we need to add the following code to the top 632 // static void * __generator_labels[] = {&&s0, &&s1, ...}; 633 // goto * __generator_labels[gen.__generator_state]; 634 const auto & loc = func->location; 635 636 const auto first_label = gen.newLabel("generator"); 637 638 // for each label add to declaration 639 std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) }; 640 for(const auto & label : labels) { 641 inits.push_back( 642 new SingleInit( 643 new LabelAddressExpr( label ) 644 ) 645 ); 646 } 647 auto init = new ListInit(std::move(inits), noDesignators, true); 648 labels.clear(); 649 650 // create decl 651 auto decl = new ObjectDecl( 652 "__generator_labels", 653 Type::StorageClasses( Type::Static ), 654 LinkageSpec::AutoGen, 655 nullptr, 656 new ArrayType( 657 Type::Qualifiers(), 658 new PointerType( 659 Type::Qualifiers(), 660 new VoidType( Type::Qualifiers() ) 661 ), 662 nullptr, 663 false, false 664 ), 665 init 666 ); 667 668 // create the goto 669 assert(in_generator); 670 671 auto go_decl = new ObjectDecl( 672 "__generator_label", 673 noStorageClasses, 674 LinkageSpec::AutoGen, 675 nullptr, 676 new PointerType( 677 Type::Qualifiers(), 678 new VoidType( Type::Qualifiers() ) 679 ), 680 new SingleInit( 681 new UntypedExpr( 682 new NameExpr("?[?]"), 683 { 684 new NameExpr("__generator_labels"), 685 new UntypedMemberExpr( 686 new NameExpr("__generator_state"), 687 new VariableExpr( in_generator ) 688 ) 689 } 690 ) 691 ) 692 ); 693 go_decl->location = loc; 694 695 auto go = new BranchStmt( 696 new VariableExpr( go_decl ), 697 BranchStmt::Goto 698 ); 699 go->location = loc; 700 go->computedTarget->location = loc; 701 702 auto noop = new NullStmt({ first_label }); 703 noop->location = loc; 704 705 // wrap everything in a nice compound 706 auto body = new CompoundStmt({ 707 new DeclStmt( decl ), 708 new DeclStmt( go_decl ), 709 go, 710 noop, 711 func->statements 712 }); 713 body->location = loc; 714 func->statements = body; 715 716 return func; 717 } 718 719 Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) { 720 SuspendStmt::Type type = stmt->type; 721 if(type == SuspendStmt::None) { 722 // This suspend has a implicit target, find it 723 type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine; 724 } 725 726 // Check that the target makes sense 727 if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type."); 728 729 // Act appropriately 730 switch(type) { 731 case SuspendStmt::Generator: return make_generator_suspend(stmt); 732 case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt); 733 default: abort(); 734 } 735 } 736 737 Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) { 738 assert(in_generator); 739 // Target code is : 740 // gen.__generator_state = X; 741 // { THEN } 742 // return; 743 // __gen_X:; 744 745 // Save the location and delete the old statement, we only need the location from this point on 746 auto loc = stmt->location; 747 748 // Build the label and get its index 749 auto label = make_label(); 750 751 // Create the context saving statement 752 auto save = new ExprStmt( new UntypedExpr( 753 new NameExpr( "?=?" ), 754 { 755 new UntypedMemberExpr( 756 new NameExpr("__generator_state"), 757 new VariableExpr( in_generator ) 758 ), 759 new ConstantExpr( 760 Constant::from_int( label.idx ) 761 ) 762 } 763 )); 764 assert(save->expr); 765 save->location = loc; 766 stmtsToAddBefore.push_back( save ); 767 768 // if we have a then add it here 769 auto then = stmt->then; 770 stmt->then = nullptr; 771 delete stmt; 772 if(then) stmtsToAddBefore.push_back( then ); 773 774 // Create the return statement 775 auto ret = new ReturnStmt( nullptr ); 776 ret->location = loc; 777 stmtsToAddBefore.push_back( ret ); 778 779 // Create the null statement with the created label 780 auto noop = new NullStmt({ label.obj }); 781 noop->location = loc; 782 783 // Return the null statement to take the place of the previous statement 784 return noop; 785 } 786 787 Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) { 788 if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented."); 789 790 // Save the location and delete the old statement, we only need the location from this point on 791 auto loc = stmt->location; 792 delete stmt; 793 794 // Create the call expression 795 if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n"); 796 auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) ); 797 expr->location = loc; 798 799 // Change this statement into a regular expr 800 assert(expr); 801 auto nstmt = new ExprStmt( expr ); 802 nstmt->location = loc; 803 return nstmt; 804 } 805 451 806 452 807 //============================================================================================= … … 458 813 bool first = false; 459 814 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first ); 460 bool isDtor = CodeGen::isDestructor( decl->name );815 bool const isDtor = CodeGen::isDestructor( decl->name ); 461 816 462 817 // Is this function relevant to monitors … … 506 861 507 862 // Instrument the body 508 if( isDtor ) { 509 addDtorStatments( decl, body, mutexArgs ); 863 if ( isDtor && isThread( mutexArgs.front() ) ) { 864 if( !thread_guard_decl ) { 865 SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" ); 866 } 867 addThreadDtorStatements( decl, body, mutexArgs ); 868 } 869 else if ( isDtor ) { 870 addDtorStatements( decl, body, mutexArgs ); 510 871 } 511 872 else { 512 addStat ments( decl, body, mutexArgs );873 addStatements( decl, body, mutexArgs ); 513 874 } 514 875 } … … 516 877 void MutexKeyword::postvisit(StructDecl* decl) { 517 878 518 if( decl->name == " monitor_desc" && decl->body ) {879 if( decl->name == "$monitor" && decl->body ) { 519 880 assert( !monitor_decl ); 520 881 monitor_decl = decl; … … 527 888 assert( !dtor_guard_decl ); 528 889 dtor_guard_decl = decl; 890 } 891 else if( decl->name == "thread_dtor_guard_t" && decl->body ) { 892 assert( !thread_guard_decl ); 893 thread_guard_decl = decl; 529 894 } 530 895 } … … 565 930 } 566 931 567 void MutexKeyword::addDtorStat ments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {932 void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 568 933 Type * arg_type = args.front()->get_type()->clone(); 569 934 arg_type->set_mutex( false ); … … 583 948 new SingleInit( new UntypedExpr( 584 949 new NameExpr( "get_monitor" ), 585 { new CastExpr( new VariableExpr( args.front() ), arg_type ) }950 { new CastExpr( new VariableExpr( args.front() ), arg_type, false ) } 586 951 )) 587 952 ); … … 604 969 { 605 970 new SingleInit( new AddressExpr( new VariableExpr( monitors ) ) ), 606 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) ) 971 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) ), 972 new SingleInit( new ConstantExpr( Constant::from_bool( false ) ) ) 607 973 }, 608 974 noDesignators, … … 612 978 ); 613 979 614 //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) }; 615 body->push_front( new DeclStmt( monitors) ); 616 } 617 618 void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 980 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) }; 981 body->push_front( new DeclStmt( monitors ) ); 982 } 983 984 void MutexKeyword::addThreadDtorStatements( 985 FunctionDecl*, CompoundStmt * body, 986 const std::list<DeclarationWithType * > & args ) { 987 assert( args.size() == 1 ); 988 DeclarationWithType * arg = args.front(); 989 Type * arg_type = arg->get_type()->clone(); 990 assert( arg_type->get_mutex() ); 991 arg_type->set_mutex( false ); 992 993 // thread_dtor_guard_t __guard = { this, intptr( 0 ) }; 994 body->push_front( 995 new DeclStmt( new ObjectDecl( 996 "__guard", 997 noStorageClasses, 998 LinkageSpec::Cforall, 999 nullptr, 1000 new StructInstType( 1001 noQualifiers, 1002 thread_guard_decl 1003 ), 1004 new ListInit( 1005 { 1006 new SingleInit( new CastExpr( new VariableExpr( arg ), arg_type ) ), 1007 new SingleInit( new UntypedExpr( 1008 new NameExpr( "intptr" ), { 1009 new ConstantExpr( Constant::from_int( 0 ) ), 1010 } 1011 ) ), 1012 }, 1013 noDesignators, 1014 true 1015 ) 1016 )) 1017 ); 1018 } 1019 1020 void MutexKeyword::addStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) { 619 1021 ObjectDecl * monitors = new ObjectDecl( 620 1022 "__monitors", … … 641 1043 return new SingleInit( new UntypedExpr( 642 1044 new NameExpr( "get_monitor" ), 643 { new CastExpr( new VariableExpr( var ), type ) }1045 { new CastExpr( new VariableExpr( var ), type, false ) } 644 1046 ) ); 645 1047 }) … … 665 1067 new SingleInit( new VariableExpr( monitors ) ), 666 1068 new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ), 667 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )1069 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) ) 668 1070 }, 669 1071 noDesignators, … … 673 1075 ); 674 1076 675 // monitor_desc* __monitors[] = { get_monitor(a), get_monitor(b) };1077 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) }; 676 1078 body->push_front( new DeclStmt( monitors) ); 677 1079 } … … 681 1083 //============================================================================================= 682 1084 void ThreadStarter::previsit( StructDecl * decl ) { 683 if( decl->name == " thread_desc" && decl->body ) {1085 if( decl->name == "$thread" && decl->body ) { 684 1086 assert( !thread_decl ); 685 1087 thread_decl = decl; … … 727 1129 // tab-width: 4 // 728 1130 // End: // 1131 -
src/Concurrency/Waitfor.cc
rbdfc032 reef8dfb 244 244 decl_mask = decl; 245 245 } 246 else if( decl->name == " monitor_desc" ) {246 else if( decl->name == "$monitor" ) { 247 247 assert( !decl_monitor ); 248 248 decl_monitor = decl; … … 384 384 decl_monitor 385 385 ) 386 ) 386 ), 387 false 387 388 ); 388 389 … … 408 409 new CompoundStmt({ 409 410 makeAccStatement( acceptables, index, "is_dtor", detectIsDtor( clause.target.function ) , indexer ), 410 makeAccStatement( acceptables, index, "func" , new CastExpr( clause.target.function, fptr_t ), indexer ),411 makeAccStatement( acceptables, index, "func" , new CastExpr( clause.target.function, fptr_t, false ) , indexer ), 411 412 makeAccStatement( acceptables, index, "data" , new VariableExpr( monitors ) , indexer ), 412 413 makeAccStatement( acceptables, index, "size" , new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ), indexer ), … … 531 532 decl_mask 532 533 ) 533 ) 534 ), 535 false 534 536 ), 535 537 timeout -
src/Concurrency/module.mk
rbdfc032 reef8dfb 15 15 ############################################################################### 16 16 17 SRC += Concurrency/Keywords.cc Concurrency/ Waitfor.cc17 SRC += Concurrency/Keywords.cc Concurrency/Keywords.h Concurrency/Waitfor.cc Concurrency/Waitfor.h 18 18 SRCDEMANGLE += Concurrency/Keywords.cc 19 19 -
src/ControlStruct/ExceptTranslate.cc
rbdfc032 reef8dfb 9 9 // Author : Andrew Beach 10 10 // Created On : Wed Jun 14 16:49:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 23:40:15 201913 // Update Count : 1 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Jun 24 11:18:00 2020 13 // Update Count : 17 14 14 // 15 15 … … 64 64 } 65 65 66 class ExceptionMutatorCore : public WithGuards { 67 enum Context { NoHandler, TerHandler, ResHandler }; 68 69 // Also need to handle goto, break & continue. 70 // They need to be cut off in a ResHandler, until we enter another 71 // loop, switch or the goto stays within the function. 72 73 Context cur_context; 74 75 // The current (innermost) termination handler exception declaration. 76 ObjectDecl * handler_except_decl; 77 66 class ThrowMutatorCore : public WithGuards { 67 ObjectDecl * terminate_handler_except; 68 enum Context { NoHandler, TerHandler, ResHandler } cur_context; 69 70 // The helper functions for code/syntree generation. 71 Statement * create_either_throw( 72 ThrowStmt * throwStmt, const char * throwFunc ); 73 Statement * create_terminate_rethrow( ThrowStmt * throwStmt ); 74 75 public: 76 ThrowMutatorCore() : 77 terminate_handler_except( nullptr ), 78 cur_context( NoHandler ) 79 {} 80 81 void premutate( CatchStmt *catchStmt ); 82 Statement * postmutate( ThrowStmt *throwStmt ); 83 }; 84 85 // ThrowStmt Mutation Helpers 86 87 Statement * ThrowMutatorCore::create_either_throw( 88 ThrowStmt * throwStmt, const char * throwFunc ) { 89 // `throwFunc`( `throwStmt->get_name()` ); 90 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) ); 91 call->get_args().push_back( throwStmt->get_expr() ); 92 throwStmt->set_expr( nullptr ); 93 delete throwStmt; 94 return new ExprStmt( call ); 95 } 96 97 Statement * ThrowMutatorCore::create_terminate_rethrow( 98 ThrowStmt *throwStmt ) { 99 // { `terminate_handler_except` = 0p; __rethrow_terminate(); } 100 assert( nullptr == throwStmt->get_expr() ); 101 assert( terminate_handler_except ); 102 103 CompoundStmt * result = new CompoundStmt(); 104 result->labels = throwStmt->labels; 105 result->push_back( new ExprStmt( UntypedExpr::createAssign( 106 nameOf( terminate_handler_except ), 107 new ConstantExpr( Constant::null( 108 terminate_handler_except->get_type()->clone() 109 ) ) 110 ) ) ); 111 result->push_back( new ExprStmt( 112 new UntypedExpr( new NameExpr( "__cfaehm_rethrow_terminate" ) ) 113 ) ); 114 delete throwStmt; 115 return result; 116 } 117 118 // Visiting/Mutating Functions 119 120 void ThrowMutatorCore::premutate( CatchStmt *catchStmt ) { 121 // Validate the statement's form. 122 ObjectDecl * decl = dynamic_cast<ObjectDecl *>( catchStmt->get_decl() ); 123 // Also checking the type would be nice. 124 if ( !decl || !dynamic_cast<PointerType *>( decl->type ) ) { 125 std::string kind = (CatchStmt::Terminate == catchStmt->kind) ? "catch" : "catchResume"; 126 SemanticError( catchStmt->location, kind + " must have pointer to an exception type" ); 127 } 128 129 // Track the handler context. 130 GuardValue( cur_context ); 131 if ( CatchStmt::Terminate == catchStmt->get_kind() ) { 132 cur_context = TerHandler; 133 134 GuardValue( terminate_handler_except ); 135 terminate_handler_except = decl; 136 } else { 137 cur_context = ResHandler; 138 } 139 } 140 141 Statement * ThrowMutatorCore::postmutate( ThrowStmt *throwStmt ) { 142 // Ignoring throwStmt->get_target() for now. 143 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) { 144 if ( throwStmt->get_expr() ) { 145 return create_either_throw( throwStmt, "$throw" ); 146 } else if ( TerHandler == cur_context ) { 147 return create_terminate_rethrow( throwStmt ); 148 } else { 149 abort("Invalid throw in %s at %i\n", 150 throwStmt->location.filename.c_str(), 151 throwStmt->location.first_line); 152 } 153 } else { 154 if ( throwStmt->get_expr() ) { 155 return create_either_throw( throwStmt, "$throwResume" ); 156 } else if ( ResHandler == cur_context ) { 157 // This has to be handled later. 158 return throwStmt; 159 } else { 160 abort("Invalid throwResume in %s at %i\n", 161 throwStmt->location.filename.c_str(), 162 throwStmt->location.first_line); 163 } 164 } 165 } 166 167 class TryMutatorCore { 78 168 // The built in types used in translation. 79 169 StructDecl * except_decl; … … 82 172 83 173 // The many helper functions for code/syntree generation. 84 Statement * create_given_throw(85 const char * throwFunc, ThrowStmt * throwStmt );86 Statement * create_terminate_throw( ThrowStmt * throwStmt );87 Statement * create_terminate_rethrow( ThrowStmt * throwStmt );88 Statement * create_resume_throw( ThrowStmt * throwStmt );89 Statement * create_resume_rethrow( ThrowStmt * throwStmt );90 174 CompoundStmt * take_try_block( TryStmt * tryStmt ); 91 175 FunctionDecl * create_try_wrapper( CompoundStmt * body ); … … 101 185 FunctionDecl * create_finally_wrapper( TryStmt * tryStmt ); 102 186 ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper ); 187 Statement * create_resume_rethrow( ThrowStmt * throwStmt ); 103 188 104 189 // Types used in translation, make sure to use clone. … … 121 206 122 207 public: 123 ExceptionMutatorCore() : 124 cur_context( NoHandler ), 125 handler_except_decl( nullptr ), 208 TryMutatorCore() : 126 209 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr ), 127 210 try_func_t( noQualifiers, false ), … … 132 215 {} 133 216 134 void premutate( CatchStmt *catchStmt );135 217 void premutate( StructDecl *structDecl ); 218 Statement * postmutate( TryStmt *tryStmt ); 136 219 Statement * postmutate( ThrowStmt *throwStmt ); 137 Statement * postmutate( TryStmt *tryStmt );138 220 }; 139 221 140 void ExceptionMutatorCore::init_func_types() {222 void TryMutatorCore::init_func_types() { 141 223 assert( except_decl ); 142 224 … … 196 278 } 197 279 198 // ThrowStmt Mutation Helpers199 200 Statement * ExceptionMutatorCore::create_given_throw(201 const char * throwFunc, ThrowStmt * throwStmt ) {202 // `throwFunc`( `throwStmt->get_name` );203 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );204 call->get_args().push_back( throwStmt->get_expr() );205 throwStmt->set_expr( nullptr );206 delete throwStmt;207 return new ExprStmt( call );208 }209 210 Statement * ExceptionMutatorCore::create_terminate_throw(211 ThrowStmt *throwStmt ) {212 // __throw_terminate( `throwStmt->get_name()` ); }213 return create_given_throw( "__cfaabi_ehm__throw_terminate", throwStmt );214 }215 216 Statement * ExceptionMutatorCore::create_terminate_rethrow(217 ThrowStmt *throwStmt ) {218 // { `handler_except_decl` = NULL; __rethrow_terminate(); }219 assert( nullptr == throwStmt->get_expr() );220 assert( handler_except_decl );221 222 CompoundStmt * result = new CompoundStmt();223 result->labels = throwStmt->labels;224 result->push_back( new ExprStmt( UntypedExpr::createAssign(225 nameOf( handler_except_decl ),226 new ConstantExpr( Constant::null(227 new PointerType(228 noQualifiers,229 handler_except_decl->get_type()->clone()230 )231 ) )232 ) ) );233 result->push_back( new ExprStmt(234 new UntypedExpr( new NameExpr( "__cfaabi_ehm__rethrow_terminate" ) )235 ) );236 delete throwStmt;237 return result;238 }239 240 Statement * ExceptionMutatorCore::create_resume_throw(241 ThrowStmt *throwStmt ) {242 // __throw_resume( `throwStmt->get_name` );243 return create_given_throw( "__cfaabi_ehm__throw_resume", throwStmt );244 }245 246 Statement * ExceptionMutatorCore::create_resume_rethrow(247 ThrowStmt *throwStmt ) {248 // return false;249 Statement * result = new ReturnStmt(250 new ConstantExpr( Constant::from_bool( false ) )251 );252 result->labels = throwStmt->labels;253 delete throwStmt;254 return result;255 }256 257 280 // TryStmt Mutation Helpers 258 281 259 CompoundStmt * ExceptionMutatorCore::take_try_block( TryStmt *tryStmt ) {282 CompoundStmt * TryMutatorCore::take_try_block( TryStmt *tryStmt ) { 260 283 CompoundStmt * block = tryStmt->get_block(); 261 284 tryStmt->set_block( nullptr ); … … 263 286 } 264 287 265 FunctionDecl * ExceptionMutatorCore::create_try_wrapper(288 FunctionDecl * TryMutatorCore::create_try_wrapper( 266 289 CompoundStmt *body ) { 267 290 … … 270 293 } 271 294 272 FunctionDecl * ExceptionMutatorCore::create_terminate_catch(295 FunctionDecl * TryMutatorCore::create_terminate_catch( 273 296 CatchList &handlers ) { 274 297 std::list<CaseStmt *> handler_wrappers; … … 309 332 local_except->get_attributes().push_back( new Attribute( 310 333 "cleanup", 311 { new NameExpr( "__cfa abi_ehm__cleanup_terminate" ) }334 { new NameExpr( "__cfaehm_cleanup_terminate" ) } 312 335 ) ); 313 336 … … 350 373 // Create a single check from a moddified handler. 351 374 // except_obj is referenced, modded_handler will be freed. 352 CompoundStmt * ExceptionMutatorCore::create_single_matcher(375 CompoundStmt * TryMutatorCore::create_single_matcher( 353 376 DeclarationWithType * except_obj, CatchStmt * modded_handler ) { 354 377 // { … … 388 411 } 389 412 390 FunctionDecl * ExceptionMutatorCore::create_terminate_match(413 FunctionDecl * TryMutatorCore::create_terminate_match( 391 414 CatchList &handlers ) { 392 415 // int match(exception * except) { … … 425 448 } 426 449 427 CompoundStmt * ExceptionMutatorCore::create_terminate_caller(450 CompoundStmt * TryMutatorCore::create_terminate_caller( 428 451 FunctionDecl * try_wrapper, 429 452 FunctionDecl * terminate_catch, 430 453 FunctionDecl * terminate_match ) { 431 // { __cfa abi_ehm__try_terminate(`try`, `catch`, `match`); }454 // { __cfaehm_try_terminate(`try`, `catch`, `match`); } 432 455 433 456 UntypedExpr * caller = new UntypedExpr( new NameExpr( 434 "__cfa abi_ehm__try_terminate" ) );457 "__cfaehm_try_terminate" ) ); 435 458 std::list<Expression *>& args = caller->get_args(); 436 459 args.push_back( nameOf( try_wrapper ) ); … … 443 466 } 444 467 445 FunctionDecl * ExceptionMutatorCore::create_resume_handler(468 FunctionDecl * TryMutatorCore::create_resume_handler( 446 469 CatchList &handlers ) { 447 470 // bool handle(exception * except) { … … 480 503 } 481 504 482 CompoundStmt * ExceptionMutatorCore::create_resume_wrapper(505 CompoundStmt * TryMutatorCore::create_resume_wrapper( 483 506 Statement * wraps, 484 507 FunctionDecl * resume_handler ) { … … 486 509 487 510 // struct __try_resume_node __resume_node 488 // __attribute__((cleanup( __cfa abi_ehm__try_resume_cleanup )));511 // __attribute__((cleanup( __cfaehm_try_resume_cleanup ))); 489 512 // ** unwinding of the stack here could cause problems ** 490 513 // ** however I don't think that can happen currently ** 491 // __cfa abi_ehm__try_resume_setup( &__resume_node, resume_handler );514 // __cfaehm_try_resume_setup( &__resume_node, resume_handler ); 492 515 493 516 std::list< Attribute * > attributes; … … 495 518 std::list< Expression * > attr_params; 496 519 attr_params.push_back( new NameExpr( 497 "__cfa abi_ehm__try_resume_cleanup" ) );520 "__cfaehm_try_resume_cleanup" ) ); 498 521 attributes.push_back( new Attribute( "cleanup", attr_params ) ); 499 522 } … … 514 537 515 538 UntypedExpr *setup = new UntypedExpr( new NameExpr( 516 "__cfa abi_ehm__try_resume_setup" ) );539 "__cfaehm_try_resume_setup" ) ); 517 540 setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) ); 518 541 setup->get_args().push_back( nameOf( resume_handler ) ); … … 524 547 } 525 548 526 FunctionDecl * ExceptionMutatorCore::create_finally_wrapper(549 FunctionDecl * TryMutatorCore::create_finally_wrapper( 527 550 TryStmt * tryStmt ) { 528 // void finally() { <finally code>}551 // void finally() { `finally->block` } 529 552 FinallyStmt * finally = tryStmt->get_finally(); 530 553 CompoundStmt * body = finally->get_block(); … … 537 560 } 538 561 539 ObjectDecl * ExceptionMutatorCore::create_finally_hook(562 ObjectDecl * TryMutatorCore::create_finally_hook( 540 563 FunctionDecl * finally_wrapper ) { 541 // struct __cfa abi_ehm__cleanup_hook __finally_hook542 // __attribute__((cleanup( finally_wrapper)));564 // struct __cfaehm_cleanup_hook __finally_hook 565 // __attribute__((cleanup( `finally_wrapper` ))); 543 566 544 567 // Make Cleanup Attribute. … … 564 587 } 565 588 589 Statement * TryMutatorCore::create_resume_rethrow( ThrowStmt *throwStmt ) { 590 // return false; 591 Statement * result = new ReturnStmt( 592 new ConstantExpr( Constant::from_bool( false ) ) 593 ); 594 result->labels = throwStmt->labels; 595 delete throwStmt; 596 return result; 597 } 598 566 599 // Visiting/Mutating Functions 567 void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) { 568 // Validate the Statement's form. 569 ObjectDecl * decl = 570 dynamic_cast<ObjectDecl *>( catchStmt->get_decl() ); 571 if ( decl && true /* check decl->get_type() */ ) { 572 // Pass. 573 } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) { 574 SemanticError(catchStmt->location, "catch must have exception type"); 575 } else { 576 SemanticError(catchStmt->location, "catchResume must have exception type"); 577 } 578 579 // Track the handler context. 580 GuardValue( cur_context ); 581 if ( CatchStmt::Terminate == catchStmt->get_kind() ) { 582 cur_context = TerHandler; 583 584 GuardValue( handler_except_decl ); 585 handler_except_decl = decl; 586 } else { 587 cur_context = ResHandler; 588 } 589 } 590 591 void ExceptionMutatorCore::premutate( StructDecl *structDecl ) { 600 void TryMutatorCore::premutate( StructDecl *structDecl ) { 592 601 if ( !structDecl->has_body() ) { 593 602 // Skip children? 594 603 return; 595 } else if ( structDecl->get_name() == "__cfa abi_ehm__base_exception_t" ) {604 } else if ( structDecl->get_name() == "__cfaehm_base_exception_t" ) { 596 605 assert( nullptr == except_decl ); 597 606 except_decl = structDecl; 598 607 init_func_types(); 599 } else if ( structDecl->get_name() == "__cfa abi_ehm__try_resume_node" ) {608 } else if ( structDecl->get_name() == "__cfaehm_try_resume_node" ) { 600 609 assert( nullptr == node_decl ); 601 610 node_decl = structDecl; 602 } else if ( structDecl->get_name() == "__cfa abi_ehm__cleanup_hook" ) {611 } else if ( structDecl->get_name() == "__cfaehm_cleanup_hook" ) { 603 612 assert( nullptr == hook_decl ); 604 613 hook_decl = structDecl; 605 614 } 606 // Later we might get the exception type as well. 607 } 608 609 Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) { 610 assert( except_decl ); 611 612 // Ignoring throwStmt->get_target() for now. 613 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) { 614 if ( throwStmt->get_expr() ) { 615 return create_terminate_throw( throwStmt ); 616 } else if ( TerHandler == cur_context ) { 617 return create_terminate_rethrow( throwStmt ); 618 } else { 619 abort("Invalid throw in %s at %i\n", 620 throwStmt->location.filename.c_str(), 621 throwStmt->location.first_line); 622 } 623 } else { 624 if ( throwStmt->get_expr() ) { 625 return create_resume_throw( throwStmt ); 626 } else if ( ResHandler == cur_context ) { 627 return create_resume_rethrow( throwStmt ); 628 } else { 629 abort("Invalid throwResume in %s at %i\n", 630 throwStmt->location.filename.c_str(), 631 throwStmt->location.first_line); 632 } 633 } 634 } 635 636 Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) { 615 } 616 617 Statement * TryMutatorCore::postmutate( TryStmt *tryStmt ) { 637 618 assert( except_decl ); 638 619 assert( node_decl ); … … 688 669 } 689 670 690 void translateEHM( std::list< Declaration *> & translationUnit ) { 691 PassVisitor<ExceptionMutatorCore> translator; 671 Statement * TryMutatorCore::postmutate( ThrowStmt *throwStmt ) { 672 // Only valid `throwResume;` statements should remain. (2/3 checks) 673 assert( ThrowStmt::Resume == throwStmt->kind && ! throwStmt->expr ); 674 return create_resume_rethrow( throwStmt ); 675 } 676 677 void translateThrows( std::list< Declaration *> & translationUnit ) { 678 PassVisitor<ThrowMutatorCore> translator; 692 679 mutateAll( translationUnit, translator ); 693 680 } 681 682 void translateTries( std::list< Declaration *> & translationUnit ) { 683 PassVisitor<TryMutatorCore> translator; 684 mutateAll( translationUnit, translator ); 685 } 694 686 } -
src/ControlStruct/ExceptTranslate.h
rbdfc032 reef8dfb 9 9 // Author : Andrew Beach 10 10 // Created On : Tus Jun 06 10:13:00 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:19:23 201713 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Tus May 19 11:47:00 2020 13 // Update Count : 5 14 14 // 15 15 … … 21 21 22 22 namespace ControlStruct { 23 void translateEHM( std::list< Declaration *> & translationUnit ); 24 // Converts exception handling structures into their underlying C code. Translation does use the exception 25 // handling header, make sure it is visible wherever translation occurs. 23 void translateThrows( std::list< Declaration *> & translationUnit ); 24 /* Replaces all throw & throwResume statements with function calls. 25 * These still need to be resolved, so call this before the reslover. 26 */ 27 28 void translateTries( std::list< Declaration *> & translationUnit ); 29 /* Replaces all try blocks (and their many clauses) with function definitions and calls. 30 * This uses the exception built-ins to produce typed output and should take place after 31 * the resolver. It also produces virtual casts and should happen before they are expanded. 32 */ 26 33 } 27 34 -
src/ControlStruct/Mutate.cc
rbdfc032 reef8dfb 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Aug 4 11:39:08 201613 // Update Count : 912 // Last Modified On : Sun Feb 16 03:22:07 2020 13 // Update Count : 10 14 14 // 15 15 … … 37 37 mutateAll( translationUnit, formut ); 38 38 } 39 } // namespace Co deGen39 } // namespace ControlStruct 40 40 41 41 // Local Variables: // -
src/ControlStruct/module.mk
rbdfc032 reef8dfb 17 17 SRC_CONTROLSTRUCT = \ 18 18 ControlStruct/ForExprMutator.cc \ 19 ControlStruct/ForExprMutator.h \ 19 20 ControlStruct/LabelFixer.cc \ 21 ControlStruct/LabelFixer.h \ 20 22 ControlStruct/LabelGenerator.cc \ 23 ControlStruct/LabelGenerator.h \ 21 24 ControlStruct/MLEMutator.cc \ 22 ControlStruct/Mutate.cc 25 ControlStruct/MLEMutator.h \ 26 ControlStruct/Mutate.cc \ 27 ControlStruct/Mutate.h 23 28 24 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc 29 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc ControlStruct/ExceptTranslate.h 25 30 SRCDEMANGLE += $(SRC_CONTROLSTRUCT) 26 31 -
src/GenPoly/GenPoly.cc
rbdfc032 reef8dfb 46 46 } 47 47 48 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) { 49 for (auto ¶m : params) { 50 auto paramType = param.strict_as<ast::TypeExpr>(); 51 if (isPolyType(paramType->type, env)) return true; 52 } 53 return false; 54 } 55 48 56 /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present 49 57 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { … … 56 64 } 57 65 66 bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) { 67 for (auto ¶m : params) { 68 auto paramType = param.strict_as<ast::TypeExpr>(); 69 if (isPolyType(paramType->type, tyVars, env)) return true; 70 } 71 return false; 72 } 73 58 74 /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present 59 75 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) { … … 92 108 Type *newType = env->lookup( typeInst->get_name() ); 93 109 if ( newType ) return newType; 110 } 111 return type; 112 } 113 114 const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) { 115 if (!env) return type; 116 if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) { 117 auto newType = env->lookup(typeInst); 118 if (newType) return newType; 94 119 } 95 120 return type; … … 111 136 } 112 137 138 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env) { 139 type = replaceTypeInst( type, env ); 140 141 if ( dynamic_cast< const ast::TypeInstType * >( type ) ) { 142 return type; 143 } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 144 return isPolyType( arrayType->base, env ); 145 } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { 146 if ( hasPolyParams( structType->params, env ) ) return type; 147 } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { 148 if ( hasPolyParams( unionType->params, env ) ) return type; 149 } 150 return 0; 151 } 152 113 153 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) { 114 154 type = replaceTypeInst( type, env ); … … 126 166 } 127 167 return 0; 168 } 169 170 const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env) { 171 type = replaceTypeInst( type, env ); 172 173 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) { 174 return tyVars.find(typeInst->typeString()) != tyVars.end() ? type : nullptr; 175 } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 176 return isPolyType( arrayType->base, env ); 177 } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) { 178 if ( hasPolyParams( structType->params, env ) ) return type; 179 } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) { 180 if ( hasPolyParams( unionType->params, env ) ) return type; 181 } 182 return nullptr; 128 183 } 129 184 … … 449 504 } 450 505 506 namespace { 507 // temporary hack to avoid re-implementing anything related to TyVarMap 508 // does this work? these two structs have identical definitions. 509 inline TypeDecl::Data convData(const ast::TypeDecl::Data & data) { 510 return *reinterpret_cast<const TypeDecl::Data *>(&data); 511 } 512 } 513 451 514 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) { 452 515 // is parameter is not polymorphic, don't need to box … … 459 522 } 460 523 524 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env) { 525 // is parameter is not polymorphic, don't need to box 526 if ( ! isPolyType( param, exprTyVars ) ) return false; 527 ast::ptr<ast::Type> newType = arg; 528 if ( env ) env->apply( newType ); 529 // if the argument's type is polymorphic, we don't need to box again! 530 return ! isPolyType( newType ); 531 } 532 461 533 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) { 462 534 FunctionType * function = getFunctionType( appExpr->function->result ); … … 467 539 } 468 540 541 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env) { 542 const ast::FunctionType * function = getFunctionType(appExpr->func->result); 543 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->func->result ).c_str() ); 544 TyVarMap exprTyVars(TypeDecl::Data{}); 545 makeTyVarMap(function, exprTyVars); 546 return needsBoxing(param, arg, exprTyVars, env); 547 548 } 549 469 550 void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) { 470 551 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } ); 552 } 553 554 void addToTyVarMap( const ast::TypeInstType * tyVar, TyVarMap & tyVarMap) { 555 tyVarMap.insert(tyVar->typeString(), convData(ast::TypeDecl::Data{tyVar->base})); 471 556 } 472 557 … … 478 563 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) { 479 564 makeTyVarMap( pointer->get_base(), tyVarMap ); 565 } 566 } 567 568 void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap) { 569 if (auto ptype = dynamic_cast<const ast::FunctionType *>(type)) { 570 for (auto & tyVar : ptype->forall) { 571 assert (tyVar); 572 addToTyVarMap(tyVar, tyVarMap); 573 } 574 } 575 if (auto pointer = dynamic_cast<const ast::PointerType *>(type)) { 576 makeTyVarMap(pointer->base, tyVarMap); 480 577 } 481 578 } -
src/GenPoly/GenPoly.h
rbdfc032 reef8dfb 26 26 27 27 namespace GenPoly { 28 28 29 typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap; 29 30 30 /// Replaces a TypeInstType by its referrent in the environment, if applicable 31 31 Type* replaceTypeInst( Type* type, const TypeSubstitution* env ); … … 33 33 /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided 34 34 Type *isPolyType( Type *type, const TypeSubstitution *env = 0 ); 35 const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr); 35 36 36 37 /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided 37 38 Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 ); 39 const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env = nullptr); 38 40 39 41 /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided … … 84 86 /// true if arg requires boxing given exprTyVars 85 87 bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ); 88 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env); 86 89 87 90 /// true if arg requires boxing in the call to appExpr 88 91 bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ); 92 bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env); 89 93 90 94 /// Adds the type variable `tyVar` to `tyVarMap` … … 93 97 /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap` 94 98 void makeTyVarMap( Type *type, TyVarMap &tyVarMap ); 99 void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap); 95 100 96 101 /// Prints type variable map -
src/GenPoly/InstantiateGeneric.cc
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Thu Aug 04 18:33:00 2016 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Thu Aug 04 18:33:00 201613 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Jul 16 10:17:00 2020 13 // Update Count : 2 14 14 // 15 15 #include "InstantiateGeneric.h" … … 172 172 InstantiationMap< AggregateDecl, AggregateDecl > instantiations; 173 173 /// Set of types which are dtype-only generic (and therefore have static layout) 174 ScopedSet< AggregateDecl*> dtypeStatics;174 std::set<AggregateDecl *> dtypeStatics; 175 175 /// Namer for concrete types 176 176 UniqueName typeNamer; … … 297 297 } 298 298 299 template< typename AggrInst > 300 static AggrInst * asForward( AggrInst * decl ) { 301 if ( !decl->body ) { 302 return nullptr; 303 } 304 decl = decl->clone(); 305 decl->body = false; 306 deleteAll( decl->members ); 307 decl->members.clear(); 308 return decl; 309 } 310 299 311 void GenericInstantiator::stripDtypeParams( AggregateDecl *base, std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs ) { 300 312 substituteMembers( base->get_members(), baseParams, typeSubs ); … … 373 385 concDecl->set_body( inst->get_baseStruct()->has_body() ); 374 386 substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() ); 375 insert( inst, typeSubs, concDecl ); // must insert before recursion 387 // Forward declare before recursion. (TODO: Only when needed, #199.) 388 insert( inst, typeSubs, concDecl ); 389 if ( StructDecl *forwardDecl = asForward( concDecl ) ) { 390 declsToAddBefore.push_back( forwardDecl ); 391 } 376 392 concDecl->acceptMutator( *visitor ); // recursively instantiate members 377 393 declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first … … 423 439 concDecl->set_body( inst->get_baseUnion()->has_body() ); 424 440 substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() ); 425 insert( inst, typeSubs, concDecl ); // must insert before recursion 441 // Forward declare before recursion. (TODO: Only when needed, #199.) 442 insert( inst, typeSubs, concDecl ); 443 if ( UnionDecl *forwardDecl = asForward( concDecl ) ) { 444 declsToAddBefore.push_back( forwardDecl ); 445 } 426 446 concDecl->acceptMutator( *visitor ); // recursively instantiate members 427 447 declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first … … 485 505 void GenericInstantiator::beginScope() { 486 506 instantiations.beginScope(); 487 dtypeStatics.beginScope();488 507 } 489 508 490 509 void GenericInstantiator::endScope() { 491 510 instantiations.endScope(); 492 dtypeStatics.endScope();493 511 } 494 512 -
src/GenPoly/Specialize.cc
rbdfc032 reef8dfb 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 23:40:49 201913 // Update Count : 3 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Jul 2 17:42:00 2020 13 // Update Count : 33 14 14 // 15 15 … … 42 42 43 43 namespace GenPoly { 44 struct Specialize final : public WithConstTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> { 44 struct Specialize final : public WithConstTypeSubstitution, 45 public WithDeclsToAdd, public WithVisitorRef<Specialize> { 45 46 Expression * postmutate( ApplicationExpr *applicationExpr ); 46 47 Expression * postmutate( CastExpr *castExpr ); … … 217 218 thunkFunc->get_attributes().push_back( new Attribute( "unused" ) ); 218 219 220 // Thunks at the global level must be static to avoid collisions between files. 221 // (Conversly thunks inside a function must be unique and not static.) 222 thunkFunc->storageClasses.is_static = !isInFunction(); 223 219 224 // thread thunk parameters into call to actual function, naming thunk parameters as we go 220 225 UniqueName paramNamer( paramPrefix ); … … 248 253 } // if 249 254 250 // handle any specializations that may still be present 251 std::string oldParamPrefix = paramPrefix; 252 paramPrefix += "p"; 253 // save stmtsToAddBefore in oldStmts 254 std::list< Statement* > oldStmts; 255 oldStmts.splice( oldStmts.end(), stmtsToAddBefore ); 256 appExpr->acceptMutator( *visitor ); 257 paramPrefix = oldParamPrefix; 258 // write any statements added for recursive specializations into the thunk body 259 thunkFunc->statements->kids.splice( thunkFunc->statements->kids.end(), stmtsToAddBefore ); 260 // restore oldStmts into stmtsToAddBefore 261 stmtsToAddBefore.splice( stmtsToAddBefore.end(), oldStmts ); 255 // Handle any specializations that may still be present. 256 { 257 std::string oldParamPrefix = paramPrefix; 258 paramPrefix += "p"; 259 std::list< Declaration * > oldDecls; 260 oldDecls.splice( oldDecls.end(), declsToAddBefore ); 261 262 appExpr->acceptMutator( *visitor ); 263 // Write recursive specializations into the thunk body. 264 for ( Declaration * decl : declsToAddBefore ) { 265 thunkFunc->statements->kids.push_back( new DeclStmt( decl ) ); 266 } 267 268 declsToAddBefore = std::move( oldDecls ); 269 paramPrefix = oldParamPrefix; 270 } 262 271 263 272 // add return (or valueless expression) to the thunk … … 270 279 thunkFunc->statements->kids.push_back( appStmt ); 271 280 272 // add thunk definition to queue of statements to add273 stmtsToAddBefore.push_back( new DeclStmt( thunkFunc ));281 // Add the thunk definition (converted to DeclStmt if appproprate). 282 declsToAddBefore.push_back( thunkFunc ); 274 283 // return address of thunk function as replacement expression 275 284 return new AddressExpr( new VariableExpr( thunkFunc ) ); -
src/GenPoly/module.mk
rbdfc032 reef8dfb 16 16 17 17 SRC += GenPoly/Box.cc \ 18 GenPoly/Box.h \ 19 GenPoly/ErasableScopedMap.h \ 20 GenPoly/FindFunction.cc \ 21 GenPoly/FindFunction.h \ 18 22 GenPoly/GenPoly.cc \ 23 GenPoly/GenPoly.h \ 24 GenPoly/InstantiateGeneric.cc \ 25 GenPoly/InstantiateGeneric.h \ 26 GenPoly/Lvalue.cc \ 27 GenPoly/Lvalue.h \ 28 GenPoly/ScopedSet.h \ 19 29 GenPoly/ScrubTyVars.cc \ 20 GenPoly/ Lvalue.cc\30 GenPoly/ScrubTyVars.h \ 21 31 GenPoly/Specialize.cc \ 22 GenPoly/FindFunction.cc \ 23 GenPoly/InstantiateGeneric.cc 32 GenPoly/Specialize.h 24 33 25 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/ Lvalue.cc34 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/GenPoly.h GenPoly/Lvalue.cc GenPoly/Lvalue.h 26 35 -
src/InitTweak/FixGlobalInit.cc
rbdfc032 reef8dfb 34 34 #include "SynTree/Visitor.h" // for acceptAll, Visitor 35 35 36 #include "AST/Expr.hpp" 37 #include "AST/Node.hpp" 38 #include "AST/Pass.hpp" 39 36 40 namespace InitTweak { 37 41 class GlobalFixer : public WithShortCircuiting { … … 50 54 FunctionDecl * initFunction; 51 55 FunctionDecl * destroyFunction; 56 }; 57 58 class GlobalFixer_new : public ast::WithShortCircuiting { 59 public: 60 void previsit (const ast::ObjectDecl *); 61 void previsit (const ast::FunctionDecl *) { visit_children = false; } 62 void previsit (const ast::StructDecl *) { visit_children = false; } 63 void previsit (const ast::UnionDecl *) { visit_children = false; } 64 void previsit (const ast::EnumDecl *) { visit_children = false; } 65 void previsit (const ast::TraitDecl *) { visit_children = false; } 66 void previsit (const ast::TypeDecl *) { visit_children = false; } 67 68 std::list< ast::ptr<ast::Stmt> > initStmts; 69 std::list< ast::ptr<ast::Stmt> > destroyStmts; 52 70 }; 53 71 … … 91 109 } 92 110 111 void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) { 112 ast::Pass<GlobalFixer_new> fixer; 113 accept_all(translationUnit, fixer); 114 115 if ( !fixer.core.initStmts.empty() ) { 116 std::vector<ast::ptr<ast::Expr>> ctorParams; 117 if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int({}, 200)); 118 auto initFunction = new ast::FunctionDecl({}, "__global_init__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.initStmts)), 119 ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("constructor", std::move(ctorParams))}); 120 121 translationUnit.decls.emplace_back( initFunction ); 122 } // if 123 124 if ( !fixer.core.destroyStmts.empty() ) { 125 std::vector<ast::ptr<ast::Expr>> dtorParams; 126 if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int({}, 200)); 127 auto destroyFunction = new ast::FunctionDecl({}, "__global_destroy__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.destroyStmts)), 128 ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("destructor", std::move(dtorParams))}); 129 130 translationUnit.decls.emplace_back(destroyFunction); 131 } // if 132 } 133 93 134 void GlobalFixer::previsit( ObjectDecl *objDecl ) { 94 135 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids(); … … 112 153 } // if 113 154 if ( Statement * ctor = ctorInit->ctor ) { 155 addDataSectonAttribute( objDecl ); 114 156 initStatements.push_back( ctor ); 115 157 objDecl->init = nullptr; … … 126 168 } 127 169 170 void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) { 171 auto mutDecl = mutate(objDecl); 172 assertf(mutDecl == objDecl, "Global object decl must be unique"); 173 if ( auto ctorInit = objDecl->init.as<ast::ConstructorInit>() ) { 174 // a decision should have been made by the resolver, so ctor and init are not both non-NULL 175 assert( ! ctorInit->ctor || ! ctorInit->init ); 176 177 const ast::Stmt * dtor = ctorInit->dtor; 178 if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) { 179 // don't need to call intrinsic dtor, because it does nothing, but 180 // non-intrinsic dtors must be called 181 destroyStmts.push_front( dtor ); 182 // ctorInit->dtor = nullptr; 183 } // if 184 if ( const ast::Stmt * ctor = ctorInit->ctor ) { 185 addDataSectionAttribute(mutDecl); 186 initStmts.push_back( ctor ); 187 mutDecl->init = nullptr; 188 // ctorInit->ctor = nullptr; 189 } else if ( const ast::Init * init = ctorInit->init ) { 190 mutDecl->init = init; 191 // ctorInit->init = nullptr; 192 } else { 193 // no constructor and no initializer, which is okay 194 mutDecl->init = nullptr; 195 } // if 196 // delete ctorInit; 197 } // if 198 } 199 128 200 // only modify global variables 129 201 void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; } -
src/InitTweak/FixGlobalInit.h
rbdfc032 reef8dfb 19 19 #include <string> // for string 20 20 21 #include <AST/Fwd.hpp> 22 23 21 24 class Declaration; 22 25 … … 26 29 /// function is for library code. 27 30 void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ); 31 void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary ); 28 32 } // namespace 29 33 -
src/InitTweak/FixInit.cc
rbdfc032 reef8dfb 10 10 // Created On : Wed Jan 13 16:29:30 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:41:27 201913 // Update Count : 7712 // Last Modified On : Sun Feb 16 04:17:07 2020 13 // Update Count : 82 14 14 // 15 15 #include "FixInit.h" … … 219 219 }; 220 220 221 struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution,public WithStmtsToAdd {221 struct SplitExpressions : public WithShortCircuiting, /*public WithTypeSubstitution, */public WithStmtsToAdd { 222 222 /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places. 223 223 static void split( std::list< Declaration * > &translationUnit ); … … 745 745 } 746 746 747 // to prevent warnings ( ‘_unq0’may be used uninitialized in this function),747 // to prevent warnings ('_unq0' may be used uninitialized in this function), 748 748 // insert an appropriate zero initializer for UniqueExpr temporaries. 749 749 Initializer * makeInit( Type * t ) { … … 802 802 if ( Statement * ctor = ctorInit->get_ctor() ) { 803 803 if ( objDecl->get_storageClasses().is_static ) { 804 805 // The ojbect needs to go in the data section, regardless of dtor complexity below. 806 // The attribute works, and is meant to apply, both for leaving the static local alone, 807 // and for hoisting it out as a static global. 808 addDataSectonAttribute( objDecl ); 809 804 810 // originally wanted to take advantage of gcc nested functions, but 805 811 // we get memory errors with this approach. To remedy this, the static -
src/InitTweak/FixInit.h
rbdfc032 reef8dfb 10 10 // Created On : Wed Jan 13 16:29:30 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at Jul 22 09:31:06 201713 // Update Count : 612 // Last Modified On : Sun Feb 16 07:54:50 2020 13 // Update Count : 8 14 14 // 15 15 … … 20 20 21 21 class Declaration; 22 namespace ast { 23 struct TranslationUnit; 24 } 22 25 23 26 namespace InitTweak { 24 /// replace constructor initializers with expression statements 25 /// and unwrap basic C-style initializers 27 /// replace constructor initializers with expression statements and unwrap basic C-style initializers 26 28 void fix( std::list< Declaration * > & translationUnit, bool inLibrary ); 29 30 void fix( ast::TranslationUnit & translationUnit, bool inLibrary); 27 31 } // namespace 28 32 -
src/InitTweak/GenInit.cc
rbdfc032 reef8dfb 26 26 #include "AST/Node.hpp" 27 27 #include "AST/Stmt.hpp" 28 #include "CompilationState.h" 28 29 #include "CodeGen/OperatorTable.h" 29 30 #include "Common/PassVisitor.h" // for PassVisitor, WithGuards, WithShort... … … 121 122 }; 122 123 124 struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards { 125 /// hoist dimension from array types in object declaration so that it uses a single 126 /// const variable of type size_t, so that side effecting array dimensions are only 127 /// computed once. 128 static void hoistArrayDimension( std::list< Declaration * > & translationUnit ); 129 130 void premutate( ObjectDecl * objectDecl ); 131 DeclarationWithType * postmutate( ObjectDecl * objectDecl ); 132 void premutate( FunctionDecl *functionDecl ); 133 // should not traverse into any of these declarations to find objects 134 // that need to be constructed or destructed 135 void premutate( AggregateDecl * ) { visit_children = false; } 136 void premutate( NamedTypeDecl * ) { visit_children = false; } 137 void premutate( FunctionType * ) { visit_children = false; } 138 139 void hoist( Type * type ); 140 141 Type::StorageClasses storageClasses; 142 bool inFunction = false; 143 }; 144 123 145 void genInit( std::list< Declaration * > & translationUnit ) { 146 if (!useNewAST) { 147 HoistArrayDimension::hoistArrayDimension( translationUnit ); 148 } 149 else { 150 HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit ); 151 } 124 152 fixReturnStatements( translationUnit ); 125 HoistArrayDimension::hoistArrayDimension( translationUnit ); 126 CtorDtor::generateCtorDtor( translationUnit ); 153 154 if (!useNewAST) { 155 CtorDtor::generateCtorDtor( translationUnit ); 156 } 127 157 } 128 158 … … 196 226 arrayType->isVarLen = ! isConstExpr( arrayType->dimension ); 197 227 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects. 228 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve 229 // still try to detect constant expressions 198 230 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return; 199 231 … … 210 242 211 243 void HoistArrayDimension::premutate( FunctionDecl * ) { 244 GuardValue( inFunction ); 245 inFunction = true; 246 } 247 248 // precompute array dimension expression, because constructor generation may duplicate it, 249 // which would be incorrect if it is a side-effecting computation. 250 void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) { 251 PassVisitor<HoistArrayDimension_NoResolve> hoister; 252 mutateAll( translationUnit, hoister ); 253 } 254 255 void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) { 256 GuardValue( storageClasses ); 257 storageClasses = objectDecl->get_storageClasses(); 258 } 259 260 DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) { 261 hoist( objectDecl->get_type() ); 262 return objectDecl; 263 } 264 265 void HoistArrayDimension_NoResolve::hoist( Type * type ) { 266 // if in function, generate const size_t var 267 static UniqueName dimensionName( "_array_dim" ); 268 269 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension. 270 if ( ! inFunction ) return; 271 if ( storageClasses.is_static ) return; 272 273 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) { 274 if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist? 275 // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects. 276 // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve 277 // still try to detect constant expressions 278 if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return; 279 280 ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) ); 281 arrayDimension->get_type()->set_const( true ); 282 283 arrayType->set_dimension( new VariableExpr( arrayDimension ) ); 284 declsToAddBefore.push_back( arrayDimension ); 285 286 hoist( arrayType->get_base() ); 287 return; 288 } 289 } 290 291 void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) { 212 292 GuardValue( inFunction ); 213 293 inFunction = true; … … 245 325 } 246 326 327 // why is this not just on FunctionDecl? 247 328 void ManagedTypes::handleDWT( DeclarationWithType * dwt ) { 248 329 // if this function is a user-defined constructor or destructor, mark down the type as "managed" … … 275 356 void ManagedTypes::endScope() { managedTypes.endScope(); } 276 357 358 bool ManagedTypes_new::isManaged( const ast::Type * type ) const { 359 // references are never constructed 360 if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false; 361 if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) { 362 // tuple is also managed if any of its components are managed 363 for (auto & component : tupleType->types) { 364 if (isManaged(component)) return true; 365 } 366 } 367 // need to clear and reset qualifiers when determining if a type is managed 368 // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() ); 369 auto tmp = shallowCopy(type); 370 tmp->qualifiers = {}; 371 // delete tmp at return 372 ast::ptr<ast::Type> guard = tmp; 373 // 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) 374 return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp ); 375 } 376 377 bool ManagedTypes_new::isManaged( const ast::ObjectDecl * objDecl ) const { 378 const ast::Type * type = objDecl->type; 379 while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) { 380 // must always construct VLAs with an initializer, since this is an error in C 381 if ( at->isVarLen && objDecl->init ) return true; 382 type = at->base; 383 } 384 return isManaged( type ); 385 } 386 387 void ManagedTypes_new::handleDWT( const ast::DeclWithType * dwt ) { 388 // if this function is a user-defined constructor or destructor, mark down the type as "managed" 389 if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) { 390 auto & params = GenPoly::getFunctionType( dwt->get_type())->params; 391 assert( ! params.empty() ); 392 // Type * type = InitTweak::getPointerBase( params.front() ); 393 // assert( type ); 394 managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ); 395 } 396 } 397 398 void ManagedTypes_new::handleStruct( const ast::StructDecl * aggregateDecl ) { 399 // don't construct members, but need to take note if there is a managed member, 400 // because that means that this type is also managed 401 for ( auto & member : aggregateDecl->members ) { 402 if ( auto field = member.as<ast::ObjectDecl>() ) { 403 if ( isManaged( field ) ) { 404 // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that 405 // polymorphic constructors make generic types managed types 406 ast::StructInstType inst( aggregateDecl ); 407 managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ); 408 break; 409 } 410 } 411 } 412 } 413 414 void ManagedTypes_new::beginScope() { managedTypes.beginScope(); } 415 void ManagedTypes_new::endScope() { managedTypes.endScope(); } 416 277 417 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) { 278 418 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor … … 283 423 assert( stmts.size() <= 1 ); 284 424 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr; 425 426 } 427 428 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) { 429 assertf(objDecl, "genCtorDtor passed null objDecl"); 430 InitExpander_new srcParam(arg); 431 return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl); 285 432 } 286 433 … … 363 510 // constructable object 364 511 InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr }; 512 ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl); 365 513 366 514 ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall( 367 srcParam, new ast::VariableExpr{ loc, objDecl }, loc, "?{}", objDecl );515 srcParam, dstParam, loc, "?{}", objDecl ); 368 516 ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall( 369 nullParam, new ast::VariableExpr{ loc, objDecl }, loc, "^?{}", objDecl,517 nullParam, dstParam, loc, "^?{}", objDecl, 370 518 SymTab::LoopBackward ); 371 519 -
src/InitTweak/GenInit.h
rbdfc032 reef8dfb 33 33 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument 34 34 ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr ); 35 ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr); 35 36 36 37 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer … … 51 52 GenPoly::ScopedSet< std::string > managedTypes; 52 53 }; 54 55 class ManagedTypes_new { 56 public: 57 bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed 58 bool isManaged( const ast::Type * type ) const; // determine if type is managed 59 60 void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor 61 void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed 62 63 void beginScope(); 64 void endScope(); 65 private: 66 GenPoly::ScopedSet< std::string > managedTypes; 67 }; 53 68 } // namespace 54 69 -
src/InitTweak/InitTweak.cc
rbdfc032 reef8dfb 87 87 }; 88 88 89 struct HasDesignations_new : public ast::WithShortCircuiting { 90 bool result = false; 91 92 void previsit( const ast::Node * ) { 93 // short circuit if we already know there are designations 94 if ( result ) visit_children = false; 95 } 96 97 void previsit( const ast::Designation * des ) { 98 // short circuit if we already know there are designations 99 if ( result ) visit_children = false; 100 else if ( ! des->designators.empty() ) { 101 result = true; 102 visit_children = false; 103 } 104 } 105 }; 106 107 struct InitDepthChecker_new : public ast::WithGuards { 108 bool result = true; 109 const ast::Type * type; 110 int curDepth = 0, maxDepth = 0; 111 InitDepthChecker_new( const ast::Type * type ) : type( type ) { 112 const ast::Type * t = type; 113 while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) { 114 maxDepth++; 115 t = at->base; 116 } 117 maxDepth++; 118 } 119 void previsit( ListInit * ) { 120 curDepth++; 121 GuardAction( [this]() { curDepth--; } ); 122 if ( curDepth > maxDepth ) result = false; 123 } 124 }; 125 89 126 struct InitFlattener_old : public WithShortCircuiting { 90 127 void previsit( SingleInit * singleInit ) { … … 124 161 } 125 162 163 bool isDesignated( const ast::Init * init ) { 164 ast::Pass<HasDesignations_new> finder; 165 maybe_accept( init, finder ); 166 return finder.core.result; 167 } 168 169 bool checkInitDepth( const ast::ObjectDecl * objDecl ) { 170 ast::Pass<InitDepthChecker_new> checker( objDecl->type ); 171 maybe_accept( objDecl->init.get(), checker ); 172 return checker.core.result; 173 } 174 126 175 std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) { 127 176 ast::Pass< InitFlattener_new > flattener; 128 177 maybe_accept( init, flattener ); 129 return std::move( flattener. pass.argList );178 return std::move( flattener.core.argList ); 130 179 } 131 180 … … 358 407 if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) { 359 408 for ( const ast::Init * init : *listInit ) { 360 buildCallExpr( callExpr, index, dimension, init, out );409 buildCallExpr( shallowCopy(callExpr), index, dimension, init, out ); 361 410 } 362 411 } else { 363 buildCallExpr( callExpr, index, dimension, init, out );412 buildCallExpr( shallowCopy(callExpr), index, dimension, init, out ); 364 413 } 365 414 } else { … … 498 547 } 499 548 549 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) { 550 assertf( func, "getParamThis: nullptr ftype" ); 551 auto & params = func->params; 552 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str()); 553 return params.front().strict_as<ast::ObjectDecl>(); 554 } 555 500 556 bool tryConstruct( DeclarationWithType * dwt ) { 501 557 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt ); … … 511 567 } 512 568 569 bool tryConstruct( const ast::DeclWithType * dwt ) { 570 auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt ); 571 if ( ! objDecl ) return false; 572 return (objDecl->init == nullptr || 573 ( objDecl->init != nullptr && objDecl->init->maybeConstructed )) 574 && ! objDecl->storage.is_extern 575 && isConstructable( objDecl->type ); 576 } 577 578 bool isConstructable( const ast::Type * type ) { 579 return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type ) 580 && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type ); 581 } 582 513 583 struct CallFinder_old { 514 584 CallFinder_old( const std::list< std::string > & names ) : names( names ) {} … … 536 606 537 607 struct CallFinder_new final { 538 std::vector< ast::ptr< ast::Expr >> matches;608 std::vector< const ast::Expr * > matches; 539 609 const std::vector< std::string > names; 540 610 … … 558 628 } 559 629 560 std::vector< ast::ptr< ast::Expr >> collectCtorDtorCalls( const ast::Stmt * stmt ) {630 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) { 561 631 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 562 632 maybe_accept( stmt, finder ); 563 return std::move( finder. pass.matches );633 return std::move( finder.core.matches ); 564 634 } 565 635 … … 696 766 template <typename Predicate> 697 767 bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) { 698 std::vector< ast::ptr< ast::Expr >> callExprs = collectCtorDtorCalls( stmt );768 std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt ); 699 769 return std::all_of( callExprs.begin(), callExprs.end(), pred ); 700 770 } … … 939 1009 } 940 1010 1011 // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards 1012 // following passes may accidentally resolve this expression if returned as untyped... 1013 ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) { 1014 static ast::ptr<ast::FunctionDecl> assign = nullptr; 1015 if (!assign) { 1016 auto td = new ast::TypeDecl({}, "T", {}, nullptr, ast::TypeDecl::Dtype, true); 1017 assign = new ast::FunctionDecl({}, "?=?", {}, 1018 { new ast::ObjectDecl({}, "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))), 1019 new ast::ObjectDecl({}, "_src", new ast::TypeInstType("T", td))}, 1020 { new ast::ObjectDecl({}, "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic); 1021 } 1022 if (dst->result.as<ast::ReferenceType>()) { 1023 for (int depth = dst->result->referenceDepth(); depth > 0; depth--) { 1024 dst = new ast::AddressExpr(dst); 1025 } 1026 } 1027 else { 1028 dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {})); 1029 } 1030 if (src->result.as<ast::ReferenceType>()) { 1031 for (int depth = src->result->referenceDepth(); depth > 0; depth--) { 1032 src = new ast::AddressExpr(src); 1033 } 1034 } 1035 return new ast::ApplicationExpr(dst->location, ast::VariableExpr::functionPointer(dst->location, assign), {dst, src}); 1036 } 1037 941 1038 struct ConstExprChecker : public WithShortCircuiting { 942 1039 // most expressions are not const expr … … 979 1076 }; 980 1077 1078 struct ConstExprChecker_new : public ast::WithShortCircuiting { 1079 // most expressions are not const expr 1080 void previsit( const ast::Expr * ) { result = false; visit_children = false; } 1081 1082 void previsit( const ast::AddressExpr *addressExpr ) { 1083 visit_children = false; 1084 const ast::Expr * arg = addressExpr->arg; 1085 1086 // address of a variable or member expression is constexpr 1087 if ( ! dynamic_cast< const ast::NameExpr * >( arg ) 1088 && ! dynamic_cast< const ast::VariableExpr * >( arg ) 1089 && ! dynamic_cast< const ast::MemberExpr * >( arg ) 1090 && ! dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false; 1091 } 1092 1093 // these expressions may be const expr, depending on their children 1094 void previsit( const ast::SizeofExpr * ) {} 1095 void previsit( const ast::AlignofExpr * ) {} 1096 void previsit( const ast::UntypedOffsetofExpr * ) {} 1097 void previsit( const ast::OffsetofExpr * ) {} 1098 void previsit( const ast::OffsetPackExpr * ) {} 1099 void previsit( const ast::CommaExpr * ) {} 1100 void previsit( const ast::LogicalExpr * ) {} 1101 void previsit( const ast::ConditionalExpr * ) {} 1102 void previsit( const ast::CastExpr * ) {} 1103 void previsit( const ast::ConstantExpr * ) {} 1104 1105 void previsit( const ast::VariableExpr * varExpr ) { 1106 visit_children = false; 1107 1108 if ( auto inst = varExpr->result.as<ast::EnumInstType>() ) { 1109 long long int value; 1110 if ( inst->base->valueOf( varExpr->var, value ) ) { 1111 // enumerators are const expr 1112 return; 1113 } 1114 } 1115 result = false; 1116 } 1117 1118 bool result = true; 1119 }; 1120 981 1121 bool isConstExpr( Expression * expr ) { 982 1122 if ( expr ) { … … 998 1138 } 999 1139 1140 bool isConstExpr( const ast::Expr * expr ) { 1141 if ( expr ) { 1142 ast::Pass<ConstExprChecker_new> checker; 1143 expr->accept( checker ); 1144 return checker.core.result; 1145 } 1146 return true; 1147 } 1148 1149 bool isConstExpr( const ast::Init * init ) { 1150 if ( init ) { 1151 ast::Pass<ConstExprChecker_new> checker; 1152 init->accept( checker ); 1153 return checker.core.result; 1154 } // if 1155 // for all intents and purposes, no initializer means const expr 1156 return true; 1157 } 1158 1000 1159 bool isConstructor( const std::string & str ) { return str == "?{}"; } 1001 1160 bool isDestructor( const std::string & str ) { return str == "^?{}"; } … … 1026 1185 if ( ftype->params.size() != 2 ) return false; 1027 1186 1028 const ast::Type * t1 = getPointerBase( ftype->params.front() ->get_type());1187 const ast::Type * t1 = getPointerBase( ftype->params.front() ); 1029 1188 if ( ! t1 ) return false; 1030 const ast::Type * t2 = ftype->params.back() ->get_type();1189 const ast::Type * t2 = ftype->params.back(); 1031 1190 1032 1191 return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, ast::SymbolTable{} ); … … 1055 1214 return isCopyFunction( decl, "?{}" ); 1056 1215 } 1216 1217 void addDataSectonAttribute( ObjectDecl * objDecl ) { 1218 Type *strLitT = new PointerType( Type::Qualifiers( ), 1219 new BasicType( Type::Qualifiers( ), BasicType::Char ) ); 1220 std::list< Expression * > attr_params; 1221 attr_params.push_back( 1222 new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) ); 1223 objDecl->attributes.push_back(new Attribute("section", attr_params)); 1224 } 1225 1226 void addDataSectionAttribute( ast::ObjectDecl * objDecl ) { 1227 auto strLitT = new ast::PointerType(new ast::BasicType(ast::BasicType::Char)); 1228 objDecl->attributes.push_back(new ast::Attribute("section", {new ast::ConstantExpr(objDecl->location, strLitT, "\".data#\"", std::nullopt)})); 1229 } 1230 1057 1231 } -
src/InitTweak/InitTweak.h
rbdfc032 reef8dfb 38 38 /// returns the first parameter of a constructor/destructor/assignment function 39 39 ObjectDecl * getParamThis( FunctionType * ftype ); 40 const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func); 40 41 41 42 /// generate a bitwise assignment operation. 42 43 ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ); 44 45 ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src); 43 46 44 47 /// transform Initializer into an argument list that can be passed to a call expression … … 48 51 /// True if the resolver should try to construct dwt 49 52 bool tryConstruct( DeclarationWithType * dwt ); 53 bool tryConstruct( const ast::DeclWithType * dwt ); 50 54 51 55 /// True if the type can have a user-defined constructor 52 56 bool isConstructable( Type * t ); 57 bool isConstructable( const ast::Type * t ); 53 58 54 59 /// True if the Initializer contains designations 55 60 bool isDesignated( Initializer * init ); 61 bool isDesignated( const ast::Init * init ); 56 62 57 63 /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its 58 64 /// type, where the depth of its type is the number of nested ArrayTypes + 1 59 65 bool checkInitDepth( ObjectDecl * objDecl ); 66 bool checkInitDepth( const ast::ObjectDecl * objDecl ); 60 67 61 68 /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr) … … 79 86 /// get all Ctor/Dtor call expressions from a Statement 80 87 void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ); 81 std::vector< ast::ptr< ast::Expr >> collectCtorDtorCalls( const ast::Stmt * stmt );88 std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ); 82 89 83 90 /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call … … 102 109 bool isConstExpr( Expression * expr ); 103 110 bool isConstExpr( Initializer * init ); 111 112 bool isConstExpr( const ast::Expr * expr ); 113 bool isConstExpr( const ast::Init * init ); 114 115 /// Modifies objDecl to have: 116 /// __attribute__((section (".data#"))) 117 /// which makes gcc put the declared variable in the data section, 118 /// which is helpful for global constants on newer gcc versions, 119 /// so that CFA's generated initialization won't segfault when writing it via a const cast. 120 /// The trailing # is an injected assembly comment, to suppress the "a" in 121 /// .section .data,"a" 122 /// .section .data#,"a" 123 /// to avoid assembler warning "ignoring changed section attributes for .data" 124 void addDataSectonAttribute( ObjectDecl * objDecl ); 125 126 void addDataSectionAttribute( ast::ObjectDecl * objDecl ); 104 127 105 128 class InitExpander_old { -
src/InitTweak/module.mk
rbdfc032 reef8dfb 15 15 ############################################################################### 16 16 17 SRC += InitTweak/GenInit.cc \ 17 SRC += \ 18 InitTweak/FixGlobalInit.cc \ 19 InitTweak/FixGlobalInit.h \ 18 20 InitTweak/FixInit.cc \ 19 InitTweak/FixGlobalInit.cc \ 20 InitTweak/InitTweak.cc 21 InitTweak/FixInit.h \ 22 InitTweak/GenInit.cc \ 23 InitTweak/GenInit.h \ 24 InitTweak/InitTweak.cc \ 25 InitTweak/InitTweak.h \ 26 InitTweak/FixInitNew.cpp 21 27 22 SRCDEMANGLE += InitTweak/GenInit.cc \ 23 InitTweak/InitTweak.cc 28 SRCDEMANGLE += \ 29 InitTweak/GenInit.cc \ 30 InitTweak/GenInit.h \ 31 InitTweak/InitTweak.cc \ 32 InitTweak/InitTweak.h 24 33 -
src/MakeLibCfa.cc
rbdfc032 reef8dfb 10 10 // Created On : Sat May 16 10:33:33 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:41:40 201913 // Update Count : 4 212 // Last Modified On : Sun Feb 16 03:49:49 2020 13 // Update Count : 45 14 14 // 15 15 … … 96 96 97 97 FunctionDecl *funcDecl = origFuncDecl->clone(); 98 CodeGen::OperatorInfoopInfo;99 bool lookResult = CodeGen::operatorLookup( funcDecl->get_name(), opInfo);100 assert( lookResult);98 const CodeGen::OperatorInfo * opInfo; 99 opInfo = CodeGen::operatorLookup( funcDecl->get_name() ); 100 assert( opInfo ); 101 101 assert( ! funcDecl->get_statements() ); 102 102 // build a recursive call - this is okay, as the call will actually be codegen'd using operator syntax … … 120 120 121 121 Statement * stmt = nullptr; 122 switch ( opInfo .type ) {122 switch ( opInfo->type ) { 123 123 case CodeGen::OT_INDEX: 124 124 case CodeGen::OT_CALL: -
src/Makefile.am
rbdfc032 reef8dfb 20 20 21 21 SRC = main.cc \ 22 CompilationState.cc \ 23 CompilationState.h \ 22 24 MakeLibCfa.cc \ 23 CompilationState.cc 25 MakeLibCfa.h 24 26 25 27 SRCDEMANGLE = CompilationState.cc … … 66 68 ___driver_cfa_cpp_SOURCES = $(SRC) 67 69 ___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC) 70 EXTRA_DIST = include/cassert include/optional BasicTypes-gen.cc 68 71 69 72 AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++14 $(TCMALLOCFLAG) -
src/Parser/DeclarationNode.cc
rbdfc032 reef8dfb 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Dec 16 15:32:22 201913 // Update Count : 113 312 // Last Modified On : Thu Oct 8 08:03:38 2020 13 // Update Count : 1135 14 14 // 15 15 … … 1016 1016 if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) { 1017 1017 dwt->location = cur->location; 1018 * 1018 *out++ = dwt; 1019 1019 } else if ( StructDecl * agg = dynamic_cast< StructDecl * >( decl ) ) { 1020 1020 // e.g., int foo(struct S) {} … … 1022 1022 auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr ); 1023 1023 obj->location = cur->location; 1024 * 1024 *out++ = obj; 1025 1025 delete agg; 1026 1026 } else if ( UnionDecl * agg = dynamic_cast< UnionDecl * >( decl ) ) { … … 1029 1029 auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr ); 1030 1030 obj->location = cur->location; 1031 * 1031 *out++ = obj; 1032 1032 } else if ( EnumDecl * agg = dynamic_cast< EnumDecl * >( decl ) ) { 1033 1033 // e.g., int foo(enum E) {} … … 1035 1035 auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr ); 1036 1036 obj->location = cur->location; 1037 * 1037 *out++ = obj; 1038 1038 } // if 1039 1039 } catch( SemanticErrorException & e ) { … … 1115 1115 // SUE's cannot have function specifiers, either 1116 1116 // 1117 // inl ne _Noreturn struct S { ... }; // disallowed1118 // inl ne _Noreturn enum E { ... }; // disallowed1117 // inline _Noreturn struct S { ... }; // disallowed 1118 // inline _Noreturn enum E { ... }; // disallowed 1119 1119 if ( funcSpecs.any() ) { 1120 1120 SemanticError( this, "invalid function specifier for " ); -
src/Parser/ExpressionNode.cc
rbdfc032 reef8dfb 10 10 // Created On : Sat May 16 13:17:07 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 18 21:14:58 201913 // Update Count : 98112 // Last Modified On : Thu Aug 20 14:01:46 2020 13 // Update Count : 1076 14 14 // 15 15 … … 65 65 66 66 void lnthSuffix( string & str, int & type, int & ltype ) { 67 // 'u' can appear before or after length suffix 67 68 string::size_type posn = str.find_last_of( "lL" ); 68 69 69 70 if ( posn == string::npos ) return; // no suffix 70 if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long 71 71 size_t end = str.length() - 1; 72 if ( posn == end ) { type = 3; return; } // no length after 'l' => long 73 72 74 string::size_type next = posn + 1; // advance to length 73 75 if ( str[next] == '3' ) { // 32 … … 84 86 } // if 85 87 } // if 86 // remove "lL" for these cases because it may not imply long 87 str.erase( posn ); // remove length 88 89 char fix = '\0'; 90 if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ? 91 str.erase( posn ); // remove length suffix and possibly uU 92 if ( type == 5 ) { // L128 does not need uU 93 end = str.length() - 1; 94 if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove 95 } else if ( fix != '\0' ) str += fix; // put 'uU' back if removed 88 96 } // lnthSuffix 89 97 … … 108 116 } // valueToType 109 117 118 static void scanbin( string & str, unsigned long long int & v ) { 119 v = 0; 120 size_t last = str.length() - 1; // last subscript of constant 121 for ( unsigned int i = 2;; ) { // ignore prefix 122 if ( str[i] == '1' ) v |= 1; 123 i += 1; 124 if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break; 125 v <<= 1; 126 } // for 127 } // scanbin 128 110 129 Expression * build_constantInteger( string & str ) { 111 130 static const BasicType::Kind kind[2][6] = { 112 131 // short (h) must be before char (hh) because shorter type has the longer suffix 113 { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt128, },114 { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt128, },132 { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, /* BasicType::SignedInt128 */ BasicType::LongLongSignedInt, }, 133 { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, /* BasicType::UnsignedInt128 */ BasicType::LongLongUnsignedInt, }, 115 134 }; 116 135 … … 120 139 }; // lnthsInt 121 140 122 unsigned long long int v; // converted integral value 123 size_t last = str.length() - 1; // last subscript of constant 124 Expression * ret; 125 //string fred( str ); 141 string str2( "0x0" ); 142 unsigned long long int v, v2 = 0; // converted integral value 143 Expression * ret, * ret2; 126 144 127 145 int type = -1; // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128 … … 139 157 } // if 140 158 159 string::size_type posn; 160 161 // 'u' can appear before or after length suffix 162 if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true; 163 164 if ( isdigit( str[str.length() - 1] ) ) { // no suffix ? 165 lnthSuffix( str, type, ltype ); // could have length suffix 166 } else { 167 // At least one digit in integer constant, so safe to backup while looking for suffix. 168 169 posn = str.find_last_of( "pP" ); // pointer value 170 if ( posn != string::npos ) { ltype = 5; str.erase( posn, 1 ); goto FINI; } 171 172 posn = str.find_last_of( "zZ" ); // size_t 173 if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; } 174 175 posn = str.rfind( "hh" ); // char 176 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; } 177 178 posn = str.rfind( "HH" ); // char 179 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; } 180 181 posn = str.find_last_of( "hH" ); // short 182 if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; } 183 184 posn = str.find_last_of( "nN" ); // int (natural number) 185 if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; } 186 187 if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; } 188 189 lnthSuffix( str, type, ltype ); // must be after check for "ll" 190 FINI: ; 191 } // if 192 141 193 // Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate 142 194 195 #if ! defined(__SIZEOF_INT128__) 196 if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target " + str ); 197 #endif // ! __SIZEOF_INT128__ 198 143 199 if ( str[0] == '0' ) { // radix character ? 144 200 dec = false; 145 201 if ( checkX( str[1] ) ) { // hex constant ? 146 sscanf( (char *)str.c_str(), "%llx", &v ); 202 if ( type < 5 ) { // not L128 ? 203 sscanf( (char *)str.c_str(), "%llx", &v ); 204 #if defined(__SIZEOF_INT128__) 205 } else { // hex int128 constant 206 unsigned int len = str.length(); 207 if ( len > (2 + 16 + 16) ) SemanticError( yylloc, "128-bit hexadecimal constant to large " + str ); 208 if ( len <= (2 + 16) ) goto FHEX1; // hex digits < 2^64 209 str2 = "0x" + str.substr( len - 16 ); 210 sscanf( (char *)str2.c_str(), "%llx", &v2 ); 211 str = str.substr( 0, len - 16 ); 212 FHEX1: ; 213 sscanf( (char *)str.c_str(), "%llx", &v ); 214 #endif // __SIZEOF_INT128__ 215 } // if 147 216 //printf( "%llx %llu\n", v, v ); 148 217 } else if ( checkB( str[1] ) ) { // binary constant ? 149 v = 0; // compute value 150 for ( unsigned int i = 2;; ) { // ignore prefix 151 if ( str[i] == '1' ) v |= 1; 152 i += 1; 153 if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break; 154 v <<= 1; 155 } // for 218 #if defined(__SIZEOF_INT128__) 219 unsigned int len = str.length(); 220 if ( type == 5 && len > 2 + 64 ) { 221 if ( len > 2 + 64 + 64 ) SemanticError( yylloc, "128-bit binary constant to large " + str ); 222 str2 = "0b" + str.substr( len - 64 ); 223 str = str.substr( 0, len - 64 ); 224 scanbin( str2, v2 ); 225 } // if 226 #endif // __SIZEOF_INT128__ 227 scanbin( str, v ); 156 228 //printf( "%#llx %llu\n", v, v ); 157 229 } else { // octal constant 158 sscanf( (char *)str.c_str(), "%llo", &v ); 230 if ( type < 5 ) { // not L128 ? 231 sscanf( (char *)str.c_str(), "%llo", &v ); 232 #if defined(__SIZEOF_INT128__) 233 } else { // octal int128 constant 234 unsigned int len = str.length(); 235 if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large " + str ); 236 char buf[32]; 237 if ( len <= 1 + 21 ) { // value < 21 octal digitis 238 sscanf( (char *)str.c_str(), "%llo", &v ); 239 } else { 240 sscanf( &str[len - 21], "%llo", &v ); 241 __int128 val = v; // accumulate bits 242 str[len - 21] ='\0'; // shorten string 243 sscanf( &str[len == 43 ? 1 : 0], "%llo", &v ); 244 val |= (__int128)v << 63; // store bits 245 if ( len == 1 + 43 ) { // most significant 2 bits ? 246 str[2] = '\0'; // shorten string 247 sscanf( &str[1], "%llo", &v ); // process most significant 2 bits 248 val |= (__int128)v << 126; // store bits 249 } // if 250 v = val >> 64; v2 = (uint64_t)val; // replace octal constant with 2 hex constants 251 sprintf( buf, "%#llx", v2 ); 252 str2 = buf; 253 } // if 254 sprintf( buf, "%#llx", v ); 255 str = buf; 256 #endif // __SIZEOF_INT128__ 257 } // if 159 258 //printf( "%#llo %llu\n", v, v ); 160 259 } // if 161 260 } else { // decimal constant ? 162 sscanf( (char *)str.c_str(), "%llu", &v ); 261 if ( type < 5 ) { // not L128 ? 262 sscanf( (char *)str.c_str(), "%llu", &v ); 263 #if defined(__SIZEOF_INT128__) 264 } else { // decimal int128 constant 265 #define P10_UINT64 10'000'000'000'000'000'000ULL // 19 zeroes 266 unsigned int len = str.length(); 267 if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") ) 268 SemanticError( yylloc, "128-bit decimal constant to large " + str ); 269 char buf[32]; 270 if ( len <= 19 ) { // value < 19 decimal digitis 271 sscanf( (char *)str.c_str(), "%llu", &v ); 272 } else { 273 sscanf( &str[len - 19], "%llu", &v ); 274 __int128 val = v; // accumulate bits 275 str[len - 19] ='\0'; // shorten string 276 sscanf( &str[len == 39 ? 1 : 0], "%llu", &v ); 277 val += (__int128)v * (__int128)P10_UINT64; // store bits 278 if ( len == 39 ) { // most significant 2 bits ? 279 str[1] = '\0'; // shorten string 280 sscanf( &str[0], "%llu", &v ); // process most significant 2 bits 281 val += (__int128)v * (__int128)P10_UINT64 * (__int128)P10_UINT64; // store bits 282 } // if 283 v = val >> 64; v2 = (uint64_t)val; // replace decimal constant with 2 hex constants 284 sprintf( buf, "%#llx", v2 ); 285 str2 = buf; 286 } // if 287 sprintf( buf, "%#llx", v ); 288 str = buf; 289 #endif // __SIZEOF_INT128__ 290 } // if 163 291 //printf( "%llu\n", v ); 164 292 } // if 165 293 166 string::size_type posn; 167 168 if ( isdigit( str[last] ) ) { // no suffix ? 169 lnthSuffix( str, type, ltype ); // could have length suffix 170 if ( type == -1 ) { // no suffix 171 valueToType( v, dec, type, Unsigned ); 172 } // if 173 } else { 174 // At least one digit in integer constant, so safe to backup while looking for suffix. 175 176 posn = str.find_last_of( "pP" ); 177 if ( posn != string::npos ) { valueToType( v, dec, type, Unsigned ); ltype = 5; str.erase( posn, 1 ); goto FINI; } 178 179 posn = str.find_last_of( "zZ" ); 180 if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; } 181 182 // 'u' can appear before or after length suffix 183 if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true; 184 185 posn = str.rfind( "hh" ); 186 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; } 187 188 posn = str.rfind( "HH" ); 189 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; } 190 191 posn = str.find_last_of( "hH" ); 192 if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; } 193 194 posn = str.find_last_of( "nN" ); 195 if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; } 196 197 if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; } 198 199 lnthSuffix( str, type, ltype ); // must be after check for "ll" 200 if ( type == -1 ) { // only 'u' suffix ? 201 valueToType( v, dec, type, Unsigned ); 202 } // if 203 FINI: ; 204 } // if 294 if ( type == -1 ) { // no suffix => determine type from value size 295 valueToType( v, dec, type, Unsigned ); 296 } // if 297 /* printf( "%s %llo %s %llo\n", str.c_str(), v, str2.c_str(), v2 ); */ 205 298 206 299 //if ( !( 0 <= type && type <= 6 ) ) { printf( "%s %lu %d %s\n", fred.c_str(), fred.length(), type, str.c_str() ); } … … 214 307 } else if ( ltype != -1 ) { // explicit length ? 215 308 if ( ltype == 6 ) { // int128, (int128)constant 216 ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false ); 309 // ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false ); 310 ret2 = new ConstantExpr( Constant( new BasicType( noQualifiers, BasicType::LongLongSignedInt ), str2, v2 ) ); 311 ret = build_compoundLiteral( DeclarationNode::newBasicType( DeclarationNode::Int128 )->addType( DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ), 312 new InitializerNode( (InitializerNode *)(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true ) ); 217 313 } else { // explicit length, (length_type)constant 218 314 ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][ltype], false ), false ); … … 342 438 if ( str[1] == '8' ) goto Default; // utf-8 characters => array of char 343 439 // lookup type of associated typedef 344 strtype = new TypeInstType( Type::Qualifiers( Type::Const), "char16_t", false );440 strtype = new TypeInstType( Type::Qualifiers( ), "char16_t", false ); 345 441 break; 346 442 case 'U': 347 strtype = new TypeInstType( Type::Qualifiers( Type::Const), "char32_t", false );443 strtype = new TypeInstType( Type::Qualifiers( ), "char32_t", false ); 348 444 break; 349 445 case 'L': 350 strtype = new TypeInstType( Type::Qualifiers( Type::Const), "wchar_t", false );446 strtype = new TypeInstType( Type::Qualifiers( ), "wchar_t", false ); 351 447 break; 352 448 Default: // char default string type 353 449 default: 354 strtype = new BasicType( Type::Qualifiers( Type::Const), BasicType::Char );450 strtype = new BasicType( Type::Qualifiers( ), BasicType::Char ); 355 451 } // switch 356 452 ArrayType * at = new ArrayType( noQualifiers, strtype, -
src/Parser/ParseNode.h
rbdfc032 reef8dfb 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Dec 16 07:46:01 201913 // Update Count : 8 8812 // Last Modified On : Sat Oct 24 03:53:54 2020 13 // Update Count : 895 14 14 // 15 15 … … 37 37 class Attribute; 38 38 class Declaration; 39 classDeclarationNode;39 struct DeclarationNode; 40 40 class DeclarationWithType; 41 41 class ExpressionNode; 42 42 class Initializer; 43 classStatementNode;43 struct StatementNode; 44 44 45 45 //############################################################################## … … 86 86 class InitializerNode : public ParseNode { 87 87 public: 88 InitializerNode( ExpressionNode *, bool aggrp = false, 88 InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr ); 89 89 InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr ); 90 90 InitializerNode( bool isDelete ); … … 205 205 struct TypeData; 206 206 207 class DeclarationNode : public ParseNode { 208 public: 207 struct DeclarationNode : public ParseNode { 209 208 // These enumerations must harmonize with their names in DeclarationNode.cc. 210 209 enum BasicType { Void, Bool, Char, Int, Int128, … … 304 303 bool get_inLine() const { return inLine; } 305 304 DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; } 306 public: 305 307 306 DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); } 308 307 … … 360 359 //############################################################################## 361 360 362 class StatementNode final : public ParseNode { 363 public: 361 struct StatementNode final : public ParseNode { 364 362 StatementNode() { stmt = nullptr; } 365 363 StatementNode( Statement * stmt ) : stmt( stmt ) {} … … 382 380 os << stmt.get() << std::endl; 383 381 } 384 private: 382 385 383 std::unique_ptr<Statement> stmt; 386 384 }; // StatementNode … … 426 424 Statement * build_finally( StatementNode * stmt ); 427 425 Statement * build_compound( StatementNode * first ); 426 StatementNode * maybe_build_compound( StatementNode * first ); 428 427 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr ); 429 428 Statement * build_directive( std::string * directive ); 429 SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None); 430 430 WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when ); 431 431 WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing ); … … 449 449 * out++ = result; 450 450 } else { 451 assertf(false, "buildList unknown type");451 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." ); 452 452 } // if 453 453 } catch( SemanticErrorException & e ) { -
src/Parser/ParserTypes.h
rbdfc032 reef8dfb 10 10 // Created On : Sat Sep 22 08:58:10 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:33:28 201713 // Update Count : 35 012 // Last Modified On : Sat Feb 15 11:04:40 2020 13 // Update Count : 351 14 14 // 15 15 … … 27 27 // current location in the input 28 28 extern int yylineno; 29 extern char * yyfilename;29 extern char * yyfilename; 30 30 31 31 struct Location { 32 char * file;32 char * file; 33 33 int line; 34 34 }; // Location 35 35 36 36 struct Token { 37 std::string * str; // must be pointer as used in union37 std::string * str; // must be pointer as used in union 38 38 Location loc; 39 39 -
src/Parser/StatementNode.cc
rbdfc032 reef8dfb 10 10 // Created On : Sat May 16 14:59:41 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 4 09:39:25 201813 // Update Count : 3 6312 // Last Modified On : Sat Oct 24 04:20:55 2020 13 // Update Count : 383 14 14 // 15 15 … … 249 249 } // build_finally 250 250 251 SuspendStmt * build_suspend( StatementNode * then, SuspendStmt::Type type ) { 252 auto node = new SuspendStmt(); 253 254 node->type = type; 255 256 std::list< Statement * > stmts; 257 buildMoveList< Statement, StatementNode >( then, stmts ); 258 if(!stmts.empty()) { 259 assert( stmts.size() == 1 ); 260 node->then = dynamic_cast< CompoundStmt * >( stmts.front() ); 261 } 262 263 return node; 264 } 265 251 266 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) { 252 267 auto node = new WaitForStmt(); … … 330 345 } // build_compound 331 346 347 // A single statement in a control structure is always converted to a compound statement so subsequent generated code 348 // can be placed within this compound statement. Otherwise, code generation has to constantly check for a single 349 // statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a 350 // conical form for code generation. 351 StatementNode * maybe_build_compound( StatementNode * first ) { 352 // Optimization: if the control-structure statement is a compound statement, do not wrap it. 353 // e.g., if (...) {...} do not wrap the existing compound statement. 354 if ( ! dynamic_cast<CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr 355 CompoundStmt * cs = new CompoundStmt(); 356 buildMoveList( first, cs->get_kids() ); 357 return new StatementNode( cs ); 358 } // if 359 return first; 360 } // maybe_build_compound 361 332 362 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) { 333 363 std::list< Expression * > out, in; -
src/Parser/TypeData.cc
rbdfc032 reef8dfb 769 769 case AggregateDecl::Struct: 770 770 case AggregateDecl::Coroutine: 771 case AggregateDecl::Generator: 771 772 case AggregateDecl::Monitor: 772 773 case AggregateDecl::Thread: … … 899 900 ret = new TypeDecl( name, scs, typebuild( td->base ), TypeDecl::Dtype, true ); 900 901 } // if 901 buildList( td->symbolic.params, ret->get_parameters() );902 902 buildList( td->symbolic.assertions, ret->get_assertions() ); 903 903 ret->base->attributes.splice( ret->base->attributes.end(), attributes ); -
src/Parser/TypedefTable.cc
rbdfc032 reef8dfb 10 10 // Created On : Sat May 16 15:20:13 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jul 25 15:32:35 201813 // Update Count : 25 812 // Last Modified On : Sat Feb 15 08:06:36 2020 13 // Update Count : 259 14 14 // 15 15 … … 47 47 } // TypedefTable::~TypedefTable 48 48 49 bool TypedefTable::exists( const string & identifier ) {49 bool TypedefTable::exists( const string & identifier ) const { 50 50 return kindTable.find( identifier ) != kindTable.end(); 51 51 } // TypedefTable::exists 52 52 53 bool TypedefTable::existsCurr( const string & identifier ) {53 bool TypedefTable::existsCurr( const string & identifier ) const { 54 54 return kindTable.findAt( kindTable.currentScope() - 1, identifier ) != kindTable.end(); 55 55 } // TypedefTable::exists -
src/Parser/TypedefTable.h
rbdfc032 reef8dfb 10 10 // Created On : Sat May 16 15:24:36 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jul 25 15:33:55 201813 // Update Count : 11 412 // Last Modified On : Sat Feb 15 08:06:37 2020 13 // Update Count : 117 14 14 // 15 15 … … 30 30 ~TypedefTable(); 31 31 32 bool exists( const std::string & identifier ) ;33 bool existsCurr( const std::string & identifier ) ;32 bool exists( const std::string & identifier ) const; 33 bool existsCurr( const std::string & identifier ) const; 34 34 int isKind( const std::string & identifier ) const; 35 35 void makeTypedef( const std::string & name, int kind = TYPEDEFname ); -
src/Parser/lex.ll
rbdfc032 reef8dfb 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Sat Feb 1 07:16:44202013 * Update Count : 7 2412 * Last Modified On : Tue Oct 6 18:15:41 2020 13 * Update Count : 743 14 14 */ 15 15 … … 43 43 #include "TypedefTable.h" 44 44 45 string * build_postfix_name( string * name ); 46 45 47 char *yyfilename; 46 48 string *strtext; // accumulate parts of character and string constant value … … 60 62 #define IDENTIFIER_RETURN() RETURN_VAL( typedefTable.isKind( yytext ) ) 61 63 62 #ifdef HAVE_KEYWORDS_FLOATXX 64 #ifdef HAVE_KEYWORDS_FLOATXX // GCC >= 7 => keyword, otherwise typedef 63 65 #define FLOATXX(v) KEYWORD_RETURN(v); 64 66 #else 65 #define FLOATXX(v) IDENTIFIER_RETURN(); 67 #define FLOATXX(v) IDENTIFIER_RETURN(); 66 68 #endif // HAVE_KEYWORDS_FLOATXX 67 69 … … 290 292 __restrict__ { KEYWORD_RETURN(RESTRICT); } // GCC 291 293 return { KEYWORD_RETURN(RETURN); } 292 294 /* resume { KEYWORD_RETURN(RESUME); } // CFA */ 293 295 short { KEYWORD_RETURN(SHORT); } 294 296 signed { KEYWORD_RETURN(SIGNED); } … … 299 301 _Static_assert { KEYWORD_RETURN(STATICASSERT); } // C11 300 302 struct { KEYWORD_RETURN(STRUCT); } 301 /* suspend { KEYWORD_RETURN(SUSPEND); } // CFA */ 303 suspend { KEYWORD_RETURN(SUSPEND); } // CFA 302 304 switch { KEYWORD_RETURN(SWITCH); } 303 305 thread { KEYWORD_RETURN(THREAD); } // C11 … … 330 332 /* identifier */ 331 333 {identifier} { IDENTIFIER_RETURN(); } 332 "``"{identifier} "``" {// CFA333 yytext[yyleng - 2] = '\0'; yytext += 2;// SKULLDUGGERY: remove backquotes (ok to shorten?)334 "``"{identifier} { // CFA 335 yytext[yyleng] = '\0'; yytext += 2; // SKULLDUGGERY: remove backquotes (ok to shorten?) 334 336 IDENTIFIER_RETURN(); 335 337 } … … 432 434 "?"({op_unary_pre_post}|"()"|"[?]"|"{}") { IDENTIFIER_RETURN(); } 433 435 "^?{}" { IDENTIFIER_RETURN(); } 434 "?`"{identifier} { IDENTIFIER_RETURN(); } // postfix operator 436 "?`"{identifier} { // postfix operator 437 yylval.tok.str = new string( &yytext[2] ); // remove ?` 438 yylval.tok.str = build_postfix_name( yylval.tok.str ); // add prefix 439 RETURN_LOCN( typedefTable.isKind( *yylval.tok.str ) ); 440 } 435 441 "?"{op_binary_over}"?" { IDENTIFIER_RETURN(); } // binary 436 442 /* -
src/Parser/module.mk
rbdfc032 reef8dfb 17 17 BUILT_SOURCES = Parser/parser.hh 18 18 19 AM_YFLAGS = -d -t -v 19 AM_YFLAGS = -d -t -v -Wno-yacc 20 20 21 21 SRC += \ … … 23 23 Parser/ExpressionNode.cc \ 24 24 Parser/InitializerNode.cc \ 25 Parser/lex.ll \ 25 26 Parser/ParseNode.cc \ 27 Parser/ParseNode.h \ 28 Parser/parser.yy \ 29 Parser/ParserTypes.h \ 30 Parser/parserutility.cc \ 31 Parser/parserutility.h \ 26 32 Parser/StatementNode.cc \ 27 33 Parser/TypeData.cc \ 34 Parser/TypeData.h \ 28 35 Parser/TypedefTable.cc \ 29 Parser/lex.ll \ 30 Parser/parser.yy \ 31 Parser/parserutility.cc 36 Parser/TypedefTable.h 32 37 33 38 MOSTLYCLEANFILES += Parser/lex.cc Parser/parser.cc Parser/parser.hh Parser/parser.output -
src/Parser/parser.yy
rbdfc032 reef8dfb 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 1 10:04:40202013 // Update Count : 4 44012 // Last Modified On : Sat Oct 24 08:21:14 2020 13 // Update Count : 4624 14 14 // 15 15 … … 166 166 } // rebindForall 167 167 168 NameExpr * build_postfix_name( const string * name ) { 169 NameExpr * new_name = build_varref( new string( "?`" + *name ) ); 170 delete name; 171 return new_name; 168 string * build_postfix_name( string * name ) { 169 *name = string("__postfix_func_") + *name; 170 return name; 172 171 } // build_postfix_name 173 172 … … 205 204 return forCtrl( type, new string( identifier->name ), start, compop, comp, inc ); 206 205 } else { 207 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed " ); return nullptr;206 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr; 208 207 } // if 209 208 } else { 210 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed " ); return nullptr;209 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr; 211 210 } // if 212 211 } // forCtrl … … 279 278 %token OTYPE FTYPE DTYPE TTYPE TRAIT // CFA 280 279 %token SIZEOF OFFSETOF 281 // %token SUSPEND RESUME // CFA 280 // %token RESUME // CFA 281 %token SUSPEND // CFA 282 282 %token ATTRIBUTE EXTENSION // GCC 283 283 %token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN … … 329 329 %type<en> conditional_expression constant_expression assignment_expression assignment_expression_opt 330 330 %type<en> comma_expression comma_expression_opt 331 %type<en> argument_expression_list 331 %type<en> argument_expression_list_opt argument_expression default_initialize_opt 332 332 %type<ifctl> if_control_expression 333 333 %type<fctl> for_control_expression for_control_expression_list … … 370 370 %type<decl> assertion assertion_list assertion_list_opt 371 371 372 %type<en> 372 %type<en> bit_subrange_size_opt bit_subrange_size 373 373 374 374 %type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type … … 624 624 // equivalent to the old x[i,j]. 625 625 { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); } 626 | postfix_expression '{' argument_expression_list '}' // CFA, constructor call626 | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call 627 627 { 628 628 Token fn; … … 630 630 $$ = new ExpressionNode( new ConstructorExpr( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) ); 631 631 } 632 | postfix_expression '(' argument_expression_list ')'632 | postfix_expression '(' argument_expression_list_opt ')' 633 633 { $$ = new ExpressionNode( build_func( $1, $3 ) ); } 634 634 | postfix_expression '`' identifier // CFA, postfix call 635 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_ postfix_name( $3) ), $1 ) ); }635 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); } 636 636 | constant '`' identifier // CFA, postfix call 637 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_ postfix_name( $3) ), $1 ) ); }637 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), $1 ) ); } 638 638 | string_literal '`' identifier // CFA, postfix call 639 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_ postfix_name( $3) ), new ExpressionNode( $1 ) ) ); }639 { $$ = new ExpressionNode( build_func( new ExpressionNode( build_varref( build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); } 640 640 | postfix_expression '.' identifier 641 641 { $$ = new ExpressionNode( build_fieldSel( $1, build_varref( $3 ) ) ); } … … 662 662 | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal 663 663 { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); } 664 | '^' primary_expression '{' argument_expression_list '}' // CFA, destructor call664 | '^' primary_expression '{' argument_expression_list_opt '}' // CFA, destructor call 665 665 { 666 666 Token fn; … … 670 670 ; 671 671 672 argument_expression_list :672 argument_expression_list_opt: 673 673 // empty 674 674 { $$ = nullptr; } 675 675 | argument_expression 676 | argument_expression_list ',' argument_expression676 | argument_expression_list_opt ',' argument_expression 677 677 { $$ = (ExpressionNode *)($1->set_last( $3 )); } 678 678 ; … … 793 793 | '(' aggregate_control '&' ')' cast_expression // CFA 794 794 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); } 795 // VIRTUAL cannot be opt because of look ahead issues796 795 | '(' VIRTUAL ')' cast_expression // CFA 797 796 { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild< Expression >( $4 ), maybeMoveBuildType( nullptr ) ) ); } … … 919 918 conditional_expression 920 919 | unary_expression assignment_operator assignment_expression 921 { $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) ); } 920 { 921 // if ( $2 == OperKinds::AtAssn ) { 922 // SemanticError( yylloc, "C @= assignment is currently unimplemented." ); $$ = nullptr; 923 // } else { 924 $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) ); 925 // } // if 926 } 922 927 | unary_expression '=' '{' initializer_list_opt comma_opt '}' 923 928 { SemanticError( yylloc, "Initializer assignment is currently unimplemented." ); $$ = nullptr; } … … 960 965 961 966 tuple_expression_list: 962 assignment_expression_opt 963 | tuple_expression_list ',' assignment_expression_opt 967 assignment_expression 968 | '@' // CFA 969 { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; } 970 | tuple_expression_list ',' assignment_expression 964 971 { $$ = (ExpressionNode *)($1->set_last( $3 )); } 972 | tuple_expression_list ',' '@' 973 { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; } 965 974 ; 966 975 … … 1071 1080 IF '(' if_control_expression ')' statement %prec THEN 1072 1081 // explicitly deal with the shift/reduce conflict on if/else 1073 { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); }1082 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); } 1074 1083 | IF '(' if_control_expression ')' statement ELSE statement 1075 { $$ = new StatementNode( build_if( $3, $5, $7) ); }1084 { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); } 1076 1085 ; 1077 1086 … … 1121 1130 1122 1131 case_clause: // CFA 1123 case_label_list statement { $$ = $1->append_last_case( new StatementNode( build_compound( $2 )) ); }1132 case_label_list statement { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); } 1124 1133 ; 1125 1134 … … 1139 1148 iteration_statement: 1140 1149 WHILE '(' push if_control_expression ')' statement pop 1141 { $$ = new StatementNode( build_while( $4, $6) ); }1150 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); } 1142 1151 | WHILE '(' ')' statement // CFA => while ( 1 ) 1143 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), $4) ); }1152 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); } 1144 1153 | DO statement WHILE '(' comma_expression ')' ';' 1145 { $$ = new StatementNode( build_do_while( $5, $2) ); }1154 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1146 1155 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1147 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2) ); }1156 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); } 1148 1157 | FOR '(' push for_control_expression_list ')' statement pop 1149 { $$ = new StatementNode( build_for( $4, $6) ); }1158 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); } 1150 1159 | FOR '(' ')' statement // CFA => for ( ;; ) 1151 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), $4) ); }1160 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); } 1152 1161 ; 1153 1162 … … 1186 1195 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), 1187 1196 OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1188 | '=' comma_expression 1197 | '=' comma_expression // CFA 1189 1198 { $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), 1190 1199 OperKinds::LEThan, $2->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } … … 1193 1202 | comma_expression inclexcl comma_expression '~' comma_expression // CFA 1194 1203 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, $5 ); } 1204 | comma_expression ';' // CFA 1205 { $$ = forCtrl( new ExpressionNode( build_constantInteger( *new string( "0u" ) ) ), $1, nullptr, OperKinds::LThan, nullptr, nullptr ); } 1195 1206 | comma_expression ';' comma_expression // CFA 1196 1207 { $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), 1197 1208 OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } 1198 | comma_expression ';' '=' comma_expression 1209 | comma_expression ';' '=' comma_expression // CFA 1199 1210 { $$ = forCtrl( $4, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), 1200 1211 OperKinds::LEThan, $4->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); } … … 1260 1271 | RETURN '{' initializer_list_opt comma_opt '}' ';' 1261 1272 { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; } 1262 // | SUSPEND ';' 1263 // { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; } 1264 // | SUSPEND compound_statement ';' 1265 // { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; } 1273 | SUSPEND ';' 1274 { $$ = new StatementNode( build_suspend( nullptr ) ); } 1275 | SUSPEND compound_statement 1276 { $$ = new StatementNode( build_suspend( $2 ) ); } 1277 | SUSPEND COROUTINE ';' 1278 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); } 1279 | SUSPEND COROUTINE compound_statement 1280 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); } 1281 | SUSPEND GENERATOR ';' 1282 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); } 1283 | SUSPEND GENERATOR compound_statement 1284 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); } 1266 1285 | THROW assignment_expression_opt ';' // handles rethrow 1267 1286 { $$ = new StatementNode( build_throw( $2 ) ); } … … 1286 1305 // If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex". 1287 1306 mutex_statement: 1288 MUTEX '(' argument_expression_list ')' statement1307 MUTEX '(' argument_expression_list_opt ')' statement 1289 1308 { SemanticError( yylloc, "Mutex statement is currently unimplemented." ); $$ = nullptr; } 1290 1309 ; … … 1303 1322 WAITFOR '(' cast_expression ')' 1304 1323 { $$ = $3; } 1305 // | WAITFOR '(' cast_expression ',' argument_expression_list ')'1324 // | WAITFOR '(' cast_expression ',' argument_expression_list_opt ')' 1306 1325 // { $$ = (ExpressionNode *)$3->set_last( $5 ); } 1307 | WAITFOR '(' cast_expression_list ':' argument_expression_list ')'1326 | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')' 1308 1327 { $$ = (ExpressionNode *)($3->set_last( $5 )); } 1309 1328 ; … … 1312 1331 cast_expression 1313 1332 | cast_expression_list ',' cast_expression 1314 { $$ = (ExpressionNode *)($1->set_last( $3 )); } 1333 // { $$ = (ExpressionNode *)($1->set_last( $3 )); } 1334 { SemanticError( yylloc, "List of mutex member is currently unimplemented." ); $$ = nullptr; } 1315 1335 ; 1316 1336 … … 1321 1341 waitfor_clause: 1322 1342 when_clause_opt waitfor statement %prec THEN 1323 { $$ = build_waitfor( $2, $3, $1 ); }1343 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); } 1324 1344 | when_clause_opt waitfor statement WOR waitfor_clause 1325 { $$ = build_waitfor( $2, $3, $1, $5 ); }1345 { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); } 1326 1346 | when_clause_opt timeout statement %prec THEN 1327 { $$ = build_waitfor_timeout( $2, $3, $1 ); }1347 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); } 1328 1348 | when_clause_opt ELSE statement 1329 { $$ = build_waitfor_timeout( nullptr, $3, $1 ); }1349 { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); } 1330 1350 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1331 1351 | when_clause_opt timeout statement WOR ELSE statement 1332 1352 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1333 1353 | when_clause_opt timeout statement WOR when_clause ELSE statement 1334 { $$ = build_waitfor_timeout( $2, $3, $1, $7, $5 ); }1354 { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); } 1335 1355 ; 1336 1356 … … 1590 1610 // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be 1591 1611 // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name. 1592 cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' 1612 cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt 1593 1613 // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator). 1594 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ) ; }1595 | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' 1596 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 ) ; }1614 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); } 1615 | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt 1616 { $$ = DeclarationNode::newFunction( $2, $1, $5, 0 )->addQualifiers( $8 ); } 1597 1617 ; 1598 1618 … … 1655 1675 1656 1676 typedef_expression: 1657 // GCC, naming expression type: typedef name = exp; gives a name to the type of an expression1677 // deprecated GCC, naming expression type: typedef name = exp; gives a name to the type of an expression 1658 1678 TYPEDEF identifier '=' assignment_expression 1659 1679 { 1660 // $$ = DeclarationNode::newName( 0 ); // unimplemented 1661 SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr; 1680 SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr; 1662 1681 } 1663 1682 | typedef_expression pop ',' push identifier '=' assignment_expression 1664 1683 { 1665 // $$ = DeclarationNode::newName( 0 ); // unimplemented 1666 SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr; 1667 } 1668 ; 1669 1670 //c_declaration: 1671 // declaring_list pop ';' 1672 // | typedef_declaration pop ';' 1673 // | typedef_expression pop ';' // GCC, naming expression type 1674 // | sue_declaration_specifier pop ';' 1675 // ; 1676 // 1677 //declaring_list: 1678 // // A semantic check is required to ensure asm_name only appears on declarations with implicit or explicit static 1679 // // storage-class 1680 // declarator asm_name_opt initializer_opt 1681 // { 1682 // typedefTable.addToEnclosingScope( IDENTIFIER ); 1683 // $$ = ( $2->addType( $1 ))->addAsmName( $3 )->addInitializer( $4 ); 1684 // } 1685 // | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt 1686 // { 1687 // typedefTable.addToEnclosingScope( IDENTIFIER ); 1688 // $$ = $1->appendList( $1->cloneBaseType( $4->addAsmName( $5 )->addInitializer( $6 ) ) ); 1689 // } 1690 // ; 1684 SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr; 1685 } 1686 ; 1691 1687 1692 1688 c_declaration: … … 1694 1690 { $$ = distAttr( $1, $2 ); } 1695 1691 | typedef_declaration 1696 | typedef_expression // GCC, naming expression type1692 | typedef_expression // deprecated GCC, naming expression type 1697 1693 | sue_declaration_specifier 1698 1694 ; … … 2073 2069 { yyy = true; $$ = AggregateDecl::Union; } 2074 2070 | EXCEPTION // CFA 2075 { yyy = true; $$ = AggregateDecl::Exception; } 2071 // { yyy = true; $$ = AggregateDecl::Exception; } 2072 { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2076 2073 ; 2077 2074 2078 2075 aggregate_control: // CFA 2079 GENERATOR 2080 { yyy = true; $$ = AggregateDecl::Coroutine; } 2076 MONITOR 2077 { yyy = true; $$ = AggregateDecl::Monitor; } 2078 | MUTEX STRUCT 2079 { yyy = true; $$ = AggregateDecl::Monitor; } 2080 | GENERATOR 2081 { yyy = true; $$ = AggregateDecl::Generator; } 2082 | MUTEX GENERATOR 2083 { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2081 2084 | COROUTINE 2082 2085 { yyy = true; $$ = AggregateDecl::Coroutine; } 2083 | M ONITOR2084 { yyy = true; $$ = AggregateDecl::Monitor; }2086 | MUTEX COROUTINE 2087 { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2085 2088 | THREAD 2086 2089 { yyy = true; $$ = AggregateDecl::Thread; } 2090 | MUTEX THREAD 2091 { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2087 2092 ; 2088 2093 … … 2407 2412 // Overloading: function, data, and operator identifiers may be overloaded. 2408 2413 // 2409 // Type declarations: " type" is used to generate new types for declaring objects. Similarly, "dtype" is used for object2414 // Type declarations: "otype" is used to generate new types for declaring objects. Similarly, "dtype" is used for object 2410 2415 // and incomplete types, and "ftype" is used for function types. Type declarations with initializers provide 2411 2416 // definitions of new types. Type declarations with storage class "extern" provide opaque types. … … 2436 2441 type_class identifier_or_type_name 2437 2442 { typedefTable.addToScope( *$2, TYPEDEFname, "9" ); } 2438 2443 type_initializer_opt assertion_list_opt 2439 2444 { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); } 2440 2445 | type_specifier identifier_parameter_declarator … … 2463 2468 assertion 2464 2469 | assertion_list assertion 2465 { $$ = $1 ? $1->appendList( $2 ) : $2; }2470 { $$ = $1->appendList( $2 ); } 2466 2471 ; 2467 2472 … … 2750 2755 | attr_name 2751 2756 { $$ = DeclarationNode::newAttribute( $1 ); } 2752 | attr_name '(' argument_expression_list ')'2757 | attr_name '(' argument_expression_list_opt ')' 2753 2758 { $$ = DeclarationNode::newAttribute( $1, $3 ); } 2754 2759 ; -
src/ResolvExpr/AdjustExprType.cc
rbdfc032 reef8dfb 100 100 101 101 namespace { 102 struct AdjustExprType_new final : public ast::WithShortCircuiting { 102 class AdjustExprType_new final : public ast::WithShortCircuiting { 103 const ast::SymbolTable & symtab; 104 public: 103 105 const ast::TypeEnvironment & tenv; 104 const ast::SymbolTable & symtab;105 106 106 107 AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 107 : tenv( e ), symtab( syms) {}108 : symtab( syms ), tenv( e ) {} 108 109 109 void pre mutate( const ast::VoidType * ) { visit_children = false; }110 void pre mutate( const ast::BasicType * ) { visit_children = false; }111 void pre mutate( const ast::PointerType * ) { visit_children = false; }112 void pre mutate( const ast::ArrayType * ) { visit_children = false; }113 void pre mutate( const ast::FunctionType * ) { visit_children = false; }114 void pre mutate( const ast::StructInstType * ) { visit_children = false; }115 void pre mutate( const ast::UnionInstType * ) { visit_children = false; }116 void pre mutate( const ast::EnumInstType * ) { visit_children = false; }117 void pre mutate( const ast::TraitInstType * ) { visit_children = false; }118 void pre mutate( const ast::TypeInstType * ) { visit_children = false; }119 void pre mutate( const ast::TupleType * ) { visit_children = false; }120 void pre mutate( const ast::VarArgsType * ) { visit_children = false; }121 void pre mutate( const ast::ZeroType * ) { visit_children = false; }122 void pre mutate( const ast::OneType * ) { visit_children = false; }110 void previsit( const ast::VoidType * ) { visit_children = false; } 111 void previsit( const ast::BasicType * ) { visit_children = false; } 112 void previsit( const ast::PointerType * ) { visit_children = false; } 113 void previsit( const ast::ArrayType * ) { visit_children = false; } 114 void previsit( const ast::FunctionType * ) { visit_children = false; } 115 void previsit( const ast::StructInstType * ) { visit_children = false; } 116 void previsit( const ast::UnionInstType * ) { visit_children = false; } 117 void previsit( const ast::EnumInstType * ) { visit_children = false; } 118 void previsit( const ast::TraitInstType * ) { visit_children = false; } 119 void previsit( const ast::TypeInstType * ) { visit_children = false; } 120 void previsit( const ast::TupleType * ) { visit_children = false; } 121 void previsit( const ast::VarArgsType * ) { visit_children = false; } 122 void previsit( const ast::ZeroType * ) { visit_children = false; } 123 void previsit( const ast::OneType * ) { visit_children = false; } 123 124 124 const ast::Type * post mutate( const ast::ArrayType * at ) {125 const ast::Type * postvisit( const ast::ArrayType * at ) { 125 126 return new ast::PointerType{ at->base, at->qualifiers }; 126 127 } 127 128 128 const ast::Type * post mutate( const ast::FunctionType * ft ) {129 const ast::Type * postvisit( const ast::FunctionType * ft ) { 129 130 return new ast::PointerType{ ft }; 130 131 } 131 132 132 const ast::Type * post mutate( const ast::TypeInstType * inst ) {133 const ast::Type * postvisit( const ast::TypeInstType * inst ) { 133 134 // replace known function-type-variables with pointer-to-function 134 if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name) ) {135 if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) { 135 136 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) { 136 137 return new ast::PointerType{ inst }; -
src/ResolvExpr/AlternativeFinder.cc
rbdfc032 reef8dfb 131 131 132 132 void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) { 133 Indenter indent = { indentAmt }; 134 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) { 135 i->print( os, indent ); 136 os << std::endl; 133 std::vector<std::string> sorted; 134 sorted.reserve(list.size()); 135 for(const auto & c : list) { 136 std::stringstream ss; 137 c.print( ss, indentAmt ); 138 sorted.push_back(ss.str()); 139 } 140 141 std::sort(sorted.begin(), sorted.end()); 142 143 for ( const auto & s : sorted ) { 144 os << s << std::endl; 137 145 } 138 146 } … … 251 259 SemanticError( expr, "No reasonable alternatives for expression " ); 252 260 } 253 if ( mode. satisfyAssns || mode.prune ) {261 if ( mode.prune ) { 254 262 // trim candidates just to those where the assertions resolve 255 263 // - necessary pre-requisite to pruning … … 1216 1224 unify( castExpr->result, alt.expr->result, alt.env, needAssertions, 1217 1225 haveAssertions, openVars, indexer ); 1218 Cost thisCost = castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(), 1219 indexer, alt.env ); 1226 Cost thisCost = 1227 castExpr->isGenerated 1228 ? conversionCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(), indexer, alt.env ) 1229 : castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(), indexer, alt.env ); 1220 1230 PRINT( 1221 1231 std::cerr << "working on cast with result: " << castExpr->result << std::endl; … … 1292 1302 1293 1303 try { 1294 // Attempt 1 : turn (thread&)X into ( thread_desc&)X.__thrd1304 // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd 1295 1305 // Clone is purely for memory management 1296 1306 std::unique_ptr<Expression> tech1 { new UntypedMemberExpr(new NameExpr(castExpr->concrete_target.field), castExpr->arg->clone()) }; … … 1303 1313 } catch(SemanticErrorException & ) {} 1304 1314 1305 // Fallback : turn (thread&)X into ( thread_desc&)get_thread(X)1315 // Fallback : turn (thread&)X into ($thread&)get_thread(X) 1306 1316 std::unique_ptr<Expression> fallback { UntypedExpr::createDeref( new UntypedExpr(new NameExpr(castExpr->concrete_target.getter), { castExpr->arg->clone() })) }; 1307 1317 // don't prune here, since it's guaranteed all alternatives will have the same type … … 1698 1708 1699 1709 // unification run for side-effects 1700 unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer ); 1710 bool canUnify = unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer ); 1711 (void) canUnify; 1701 1712 // xxx - do some inspecting on this line... why isn't result bound to initAlt.type? 1702 1713 1703 Cost thisCost = c astCost( alt.expr->result, toType, alt.expr->get_lvalue(),1714 Cost thisCost = computeConversionCost( alt.expr->result, toType, alt.expr->get_lvalue(), 1704 1715 indexer, newEnv ); 1716 1717 PRINT( 1718 Cost legacyCost = castCost( alt.expr->result, toType, alt.expr->get_lvalue(), 1719 indexer, newEnv ); 1720 std::cerr << "Considering initialization:"; 1721 std::cerr << std::endl << " FROM: "; alt.expr->result->print(std::cerr); 1722 std::cerr << std::endl << " TO: "; toType ->print(std::cerr); 1723 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed"); 1724 std::cerr << std::endl << " Legacy cost " << legacyCost; 1725 std::cerr << std::endl << " New cost " << thisCost; 1726 std::cerr << std::endl; 1727 ) 1728 1705 1729 if ( thisCost != Cost::infinity ) { 1706 1730 // count one safe conversion for each value that is thrown away -
src/ResolvExpr/Candidate.cpp
rbdfc032 reef8dfb 41 41 42 42 void print( std::ostream & os, const CandidateList & cands, Indenter indent ) { 43 for ( const CandidateRef & cand : cands ) { 44 print( os, *cand, indent ); 45 os << std::endl; 43 std::vector<std::string> sorted; 44 sorted.reserve(cands.size()); 45 for(const auto & c : cands) { 46 std::stringstream ss; 47 print( ss, *c, indent ); 48 sorted.push_back(ss.str()); 49 } 50 51 std::sort(sorted.begin(), sorted.end()); 52 53 for ( const auto & s : sorted ) { 54 os << s << std::endl; 46 55 } 47 56 } -
src/ResolvExpr/Candidate.hpp
rbdfc032 reef8dfb 51 51 52 52 Candidate( const ast::Expr * x, const ast::TypeEnvironment & e ) 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {} 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() { 54 assert(x->result); 55 } 54 56 55 57 Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero ) 56 58 : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ), 57 need( o.need ) {} 59 need( o.need ) { 60 assert(x->result); 61 } 58 62 59 63 Candidate( 60 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 64 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 61 65 const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero ) 62 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {} 66 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) { 67 assert(x->result); 68 } 63 69 64 70 Candidate( … … 66 72 ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero ) 67 73 : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ), 68 need( n.begin(), n.end() ) {} 74 need( n.begin(), n.end() ) { 75 assert(x->result); 76 } 69 77 }; 70 78 -
src/ResolvExpr/CandidateFinder.cpp
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 14:55:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 43 43 #include "SymTab/Validate.h" // for validateType 44 44 #include "Tuples/Tuples.h" // for handleTupleAssignment 45 #include "InitTweak/InitTweak.h" // for getPointerBase 46 47 #include "Common/Stats/Counter.h" 45 48 46 49 #define PRINT( text ) if ( resolvep ) { text } … … 54 57 return new ast::CastExpr{ expr, expr->result->stripReferences() }; 55 58 } 56 59 57 60 return expr; 58 61 } … … 61 64 UniqueId globalResnSlot = 0; 62 65 63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,65 const ast:: TypeEnvironment & env66 Cost computeConversionCost( 67 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 68 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 66 69 ) { 67 70 PRINT( … … 74 77 std::cerr << std::endl; 75 78 ) 76 Cost convCost = conversionCost( argType, paramType, symtab, env );79 Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env ); 77 80 PRINT( 78 81 std::cerr << std::endl << "cost is " << convCost << std::endl; … … 107 110 108 111 /// Computes conversion cost for a given expression to a given type 109 const ast::Expr * computeExpressionConversionCost( 110 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 112 const ast::Expr * computeExpressionConversionCost( 113 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 111 114 ) { 112 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env ); 115 Cost convCost = computeConversionCost( 116 arg->result, paramType, arg->get_lvalue(), symtab, env ); 113 117 outCost += convCost; 114 118 115 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 116 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 119 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 120 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 117 121 // infer parameters and this does not currently work for the reason stated below 118 122 Cost tmpCost = convCost; … … 123 127 return new ast::CastExpr{ arg, newType }; 124 128 125 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 126 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 129 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 130 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 127 131 // once this is fixed it should be possible to resolve the cast. 128 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 129 // but it shouldn't be because this makes the conversion from DT* to DT* since 132 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 133 // but it shouldn't be because this makes the conversion from DT* to DT* since 130 134 // commontype(zero_t, DT*) is DT*, rather than nothing 131 135 132 136 // CandidateFinder finder{ symtab, env }; 133 137 // finder.find( arg, ResolvMode::withAdjustment() ); 134 // assertf( finder.candidates.size() > 0, 138 // assertf( finder.candidates.size() > 0, 135 139 // "Somehow castable expression failed to find alternatives." ); 136 // assertf( finder.candidates.size() == 1, 140 // assertf( finder.candidates.size() == 1, 137 141 // "Somehow got multiple alternatives for known cast expression." ); 138 142 // return finder.candidates.front()->expr; … … 143 147 144 148 /// Computes conversion cost for a given candidate 145 Cost computeApplicationConversionCost( 146 CandidateRef cand, const ast::SymbolTable & symtab 149 Cost computeApplicationConversionCost( 150 CandidateRef cand, const ast::SymbolTable & symtab 147 151 ) { 148 152 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); … … 167 171 if ( function->isVarArgs ) { 168 172 convCost.incUnsafe(); 169 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 173 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 174 << convCost << std::endl; ; ) 171 175 // convert reference-typed expressions into value-typed expressions 172 cand->expr = ast::mutate_field_index( 173 appExpr, &ast::ApplicationExpr::args, i, 176 cand->expr = ast::mutate_field_index( 177 appExpr, &ast::ApplicationExpr::args, i, 174 178 referenceToRvalueConversion( args[i], convCost ) ); 175 179 continue; … … 180 184 // Default arguments should be free - don't include conversion cost. 181 185 // Unwrap them here because they are not relevant to the rest of the system 182 cand->expr = ast::mutate_field_index( 186 cand->expr = ast::mutate_field_index( 183 187 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 184 188 ++param; … … 187 191 188 192 // mark conversion cost and also specialization cost of param type 189 const ast::Type * paramType = (*param)->get_type();190 cand->expr = ast::mutate_field_index( 191 appExpr, &ast::ApplicationExpr::args, i, 192 computeExpressionConversionCost( 193 args[i], paramType, symtab, cand->env, convCost ) );194 convCost.decSpec( specCost( paramType) );193 // const ast::Type * paramType = (*param)->get_type(); 194 cand->expr = ast::mutate_field_index( 195 appExpr, &ast::ApplicationExpr::args, i, 196 computeExpressionConversionCost( 197 args[i], *param, symtab, cand->env, convCost ) ); 198 convCost.decSpec( specCost( *param ) ); 195 199 ++param; // can't be in for-loop update because of the continue 196 200 } … … 198 202 if ( param != params.end() ) return Cost::infinity; 199 203 200 // specialization cost of return types can't be accounted for directly, it disables 204 // specialization cost of return types can't be accounted for directly, it disables 201 205 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 202 206 // … … 208 212 // mark type variable and specialization cost of forall clause 209 213 convCost.incVar( function->forall.size() ); 210 for ( const ast::TypeDecl * td : function->forall ) { 211 convCost.decSpec( td->assertions.size() ); 212 } 214 convCost.decSpec( function->assertions.size() ); 213 215 214 216 return convCost; 215 217 } 216 218 217 void makeUnifiableVars( 218 const ast:: ParameterizedType * type, ast::OpenVarSet & unifiableVars,219 ast::AssertionSet & need 219 void makeUnifiableVars( 220 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars, 221 ast::AssertionSet & need 220 222 ) { 221 for ( const ast::TypeDecl *tyvar : type->forall ) {222 unifiableVars[ tyvar->name ] = ast::TypeDecl::Data{ tyvar};223 for ( const ast::DeclWithType * assn : tyvar->assertions ) {224 need[ assn ].isUsed = true;225 }223 for ( auto & tyvar : type->forall ) { 224 unifiableVars[ *tyvar ] = ast::TypeDecl::Data{ tyvar->base }; 225 } 226 for ( auto & assn : type->assertions ) { 227 need[ assn ].isUsed = true; 226 228 } 227 229 } … … 254 256 255 257 ArgPack() 256 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 258 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 259 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 258 259 ArgPack( 260 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 260 261 ArgPack( 262 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 261 263 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 262 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 264 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 265 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 264 266 265 267 ArgPack( 266 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 267 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 268 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 268 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 269 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 270 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 269 271 unsigned nextExpl = 0, unsigned explAlt = 0 ) 270 272 : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ), 271 273 have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 272 274 nextExpl( nextExpl ), explAlt( explAlt ) {} 273 275 274 276 ArgPack( 275 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 277 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 278 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 277 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 278 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 279 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 280 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 279 281 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 280 282 281 283 /// true if this pack is in the middle of an exploded argument 282 284 bool hasExpl() const { return nextExpl > 0; } … … 286 288 return args[ nextArg-1 ][ explAlt ]; 287 289 } 288 290 289 291 /// Ends a tuple expression, consolidating the appropriate args 290 292 void endTuple( const std::vector< ArgPack > & packs ) { … … 307 309 308 310 /// Instantiates an argument to match a parameter, returns false if no matching results left 309 bool instantiateArgument( 310 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 311 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 312 unsigned nTuples = 0 311 bool instantiateArgument( 312 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 313 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 314 unsigned nTuples = 0 313 315 ) { 314 316 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { … … 318 320 // xxx - dropping initializer changes behaviour from previous, but seems correct 319 321 // ^^^ need to handle the case where a tuple has a default argument 320 if ( ! instantiateArgument( 322 if ( ! instantiateArgument( 321 323 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 322 324 nTuples = 0; … … 329 331 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 330 332 // paramType is a ttype, consumes all remaining arguments 331 333 332 334 // completed tuples; will be spliced to end of results to finish 333 335 std::vector< ArgPack > finalResults{}; … … 342 344 for ( std::size_t i = genStart; i < genEnd; ++i ) { 343 345 unsigned nextArg = results[i].nextArg; 344 346 345 347 // use next element of exploded tuple if present 346 348 if ( results[i].hasExpl() ) { … … 352 354 results.emplace_back( 353 355 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 354 copy( results[i].need ), copy( results[i].have ), 356 copy( results[i].need ), copy( results[i].have ), 355 357 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 356 358 results[i].explAlt ); … … 370 372 // push empty tuple expression 371 373 newResult.parent = i; 372 std::vector< ast::ptr< ast::Expr > > emptyList; 373 newResult.expr = 374 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) }; 374 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} }; 375 375 argType = newResult.expr->result; 376 376 } else { … … 400 400 401 401 // check unification for ttype before adding to final 402 if ( 403 unify( 402 if ( 403 unify( 404 404 ttype, argType, newResult.env, newResult.need, newResult.have, 405 newResult.open, symtab ) 405 newResult.open, symtab ) 406 406 ) { 407 407 finalResults.emplace_back( move( newResult ) ); … … 424 424 if ( expl.exprs.empty() ) { 425 425 results.emplace_back( 426 results[i], move( env ), copy( results[i].need ), 426 results[i], move( env ), copy( results[i].need ), 427 427 copy( results[i].have ), move( open ), nextArg + 1, expl.cost ); 428 428 429 429 continue; 430 430 } … … 432 432 // add new result 433 433 results.emplace_back( 434 i, expl.exprs.front(), move( env ), copy( results[i].need ), 435 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 434 i, expl.exprs.front(), move( env ), copy( results[i].need ), 435 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 436 436 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 437 437 } … … 479 479 480 480 results.emplace_back( 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 482 482 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 483 483 } … … 495 495 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 496 496 results.emplace_back( 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 498 498 move( need ), move( have ), move( open ), nextArg, nTuples ); 499 499 } … … 517 517 if ( expl.exprs.empty() ) { 518 518 results.emplace_back( 519 results[i], move( env ), move( need ), move( have ), move( open ), 519 results[i], move( env ), move( need ), move( have ), move( open ), 520 520 nextArg + 1, expl.cost ); 521 521 522 522 continue; 523 523 } … … 539 539 // add new result 540 540 results.emplace_back( 541 i, expr, move( env ), move( need ), move( have ), move( open ), 541 i, expr, move( env ), move( need ), move( have ), move( open ), 542 542 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 543 543 } … … 548 548 genStart = genEnd; 549 549 550 return genEnd != results.size(); 550 return genEnd != results.size(); // were any new results added? 551 551 } 552 552 553 553 /// Generate a cast expression from `arg` to `toType` 554 const ast::Expr * restructureCast( 554 const ast::Expr * restructureCast( 555 555 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 556 556 ) { 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 561 561 ) { 562 // Argument is a tuple and the target type is neither void nor a reference. Cast each 563 // member of the tuple to its corresponding target type, producing the tuple of those 564 // cast expressions. If there are more components of the tuple than components in the 565 // target type, then excess components do not come out in the result expression (but 562 // Argument is a tuple and the target type is neither void nor a reference. Cast each 563 // member of the tuple to its corresponding target type, producing the tuple of those 564 // cast expressions. If there are more components of the tuple than components in the 565 // target type, then excess components do not come out in the result expression (but 566 566 // UniqueExpr ensures that the side effects will still be produced) 567 567 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 568 // expressions which may contain side effects require a single unique instance of 568 // expressions which may contain side effects require a single unique instance of 569 569 // the expression 570 570 arg = new ast::UniqueExpr{ arg->location, arg }; … … 574 574 // cast each component 575 575 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 576 components.emplace_back( 576 components.emplace_back( 577 577 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 578 578 } … … 594 594 595 595 /// Actually visits expressions to find their candidate interpretations 596 struct Finder final : public ast::WithShortCircuiting { 596 class Finder final : public ast::WithShortCircuiting { 597 const ast::SymbolTable & symtab; 598 public: 599 static size_t traceId; 597 600 CandidateFinder & selfFinder; 598 const ast::SymbolTable & symtab;599 601 CandidateList & candidates; 600 602 const ast::TypeEnvironment & tenv; 601 603 ast::ptr< ast::Type > & targetType; 602 604 605 enum Errors { 606 NotFound, 607 NoMatch, 608 ArgsToFew, 609 ArgsToMany, 610 RetsToFew, 611 RetsToMany, 612 NoReason 613 }; 614 615 struct { 616 Errors code = NotFound; 617 } reason; 618 603 619 Finder( CandidateFinder & f ) 604 : s elfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),620 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 605 621 targetType( f.targetType ) {} 606 622 607 623 void previsit( const ast::Node * ) { visit_children = false; } 608 624 … … 611 627 void addCandidate( Args &&... args ) { 612 628 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 629 reason.code = NoReason; 613 630 } 614 631 … … 639 656 640 657 /// Completes a function candidate with arguments located 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 658 void validateFunctionCandidate( 659 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 660 CandidateList & out 644 661 ) { 645 ast::ApplicationExpr * appExpr = 662 ast::ApplicationExpr * appExpr = 646 663 new ast::ApplicationExpr{ func->expr->location, func->expr }; 647 664 // sum cost and accumulate arguments … … 657 674 appExpr->args = move( vargs ); 658 675 // build and validate new candidate 659 auto newCand = 676 auto newCand = 660 677 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 661 678 PRINT( … … 669 686 /// Builds a list of candidates for a function, storing them in out 670 687 void makeFunctionCandidates( 671 const CandidateRef & func, const ast::FunctionType * funcType, 688 const CandidateRef & func, const ast::FunctionType * funcType, 672 689 const ExplodedArgs_new & args, CandidateList & out 673 690 ) { … … 676 693 ast::TypeEnvironment funcEnv{ func->env }; 677 694 makeUnifiableVars( funcType, funcOpen, funcNeed ); 678 // add all type variables as open variables now so that those not used in the parameter679 // list are still considered open695 // add all type variables as open variables now so that those not used in the 696 // parameter list are still considered open 680 697 funcEnv.add( funcType->forall ); 681 698 682 699 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) { 683 700 // attempt to narrow based on expected target type 684 const ast::Type * returnType = funcType->returns.front() ->get_type();685 if ( ! unify( 686 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 701 const ast::Type * returnType = funcType->returns.front(); 702 if ( ! unify( 703 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 687 704 ) { 688 705 // unification failed, do not pursue this candidate … … 696 713 std::size_t genStart = 0; 697 714 698 for ( const ast::DeclWithType * param : funcType->params ) { 699 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param ); 700 // Try adding the arguments corresponding to the current parameter to the existing 715 // xxx - how to handle default arg after change to ftype representation? 716 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) { 717 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) { 718 // function may have default args only if directly calling by name 719 // must use types on candidate however, due to RenameVars substitution 720 auto nParams = funcType->params.size(); 721 722 for (size_t i=0; i<nParams; ++i) { 723 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 724 if (!instantiateArgument( 725 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 726 } 727 goto endMatch; 728 } 729 } 730 for ( const auto & param : funcType->params ) { 731 // Try adding the arguments corresponding to the current parameter to the existing 701 732 // matches 702 if ( ! instantiateArgument( 703 obj->type, obj->init, args, results, genStart, symtab ) ) return; 704 } 705 733 // no default args for indirect calls 734 if ( ! instantiateArgument( 735 param, nullptr, args, results, genStart, symtab ) ) return; 736 } 737 738 endMatch: 706 739 if ( funcType->isVarArgs ) { 707 740 // append any unused arguments to vararg pack … … 750 783 if ( expl.exprs.empty() ) { 751 784 results.emplace_back( 752 results[i], move( env ), copy( results[i].need ), 753 copy( results[i].have ), move( open ), nextArg + 1, 785 results[i], move( env ), copy( results[i].need ), 786 copy( results[i].have ), move( open ), nextArg + 1, 754 787 expl.cost ); 755 788 … … 760 793 results.emplace_back( 761 794 i, expl.exprs.front(), move( env ), copy( results[i].need ), 762 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 795 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 763 796 expl.exprs.size() == 1 ? 0 : 1, j ); 764 797 } … … 780 813 /// Adds implicit struct-conversions to the alternative list 781 814 void addAnonConversions( const CandidateRef & cand ) { 782 // adds anonymous member interpretations whenever an aggregate value type is seen. 783 // it's okay for the aggregate expression to have reference type -- cast it to the 815 // adds anonymous member interpretations whenever an aggregate value type is seen. 816 // it's okay for the aggregate expression to have reference type -- cast it to the 784 817 // base type to treat the aggregate as the referenced value 785 818 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 786 819 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 787 820 cand->env.apply( aggrType ); 788 821 789 822 if ( aggrType.as< ast::ReferenceType >() ) { 790 823 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; … … 799 832 800 833 /// Adds aggregate member interpretations 801 void addAggMembers( 802 const ast:: ReferenceToType * aggrInst, const ast::Expr * expr,803 const Candidate & cand, const Cost & addedCost, const std::string & name 834 void addAggMembers( 835 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 836 const Candidate & cand, const Cost & addedCost, const std::string & name 804 837 ) { 805 838 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 806 839 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 807 CandidateRef newCand = std::make_shared<Candidate>( 840 CandidateRef newCand = std::make_shared<Candidate>( 808 841 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 809 // add anonymous member interpretations whenever an aggregate value type is seen 842 // add anonymous member interpretations whenever an aggregate value type is seen 810 843 // as a member expression 811 844 addAnonConversions( newCand ); … … 815 848 816 849 /// Adds tuple member interpretations 817 void addTupleMembers( 818 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 819 const Cost & addedCost, const ast::Expr * member 850 void addTupleMembers( 851 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 852 const Cost & addedCost, const ast::Expr * member 820 853 ) { 821 854 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 822 // get the value of the constant expression as an int, must be between 0 and the 855 // get the value of the constant expression as an int, must be between 0 and the 823 856 // length of the tuple to have meaning 824 857 long long val = constantExpr->intValue(); 825 858 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 826 859 addCandidate( 827 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 860 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 828 861 addedCost ); 829 862 } … … 832 865 833 866 void postvisit( const ast::UntypedExpr * untypedExpr ) { 834 CandidateFinder funcFinder{ symtab, tenv }; 835 funcFinder.find( untypedExpr->func, ResolvMode::withAdjustment() ); 836 // short-circuit if no candidates 837 if ( funcFinder.candidates.empty() ) return; 838 839 std::vector< CandidateFinder > argCandidates = 867 std::vector< CandidateFinder > argCandidates = 840 868 selfFinder.findSubExprs( untypedExpr->args ); 841 869 842 870 // take care of possible tuple assignments 843 871 // if not tuple assignment, handled as normal function call 844 872 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates ); 873 874 CandidateFinder funcFinder{ symtab, tenv }; 875 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) { 876 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 877 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) { 878 assertf(!argCandidates.empty(), "special function call without argument"); 879 for (auto & firstArgCand: argCandidates[0]) { 880 ast::ptr<ast::Type> argType = firstArgCand->expr->result; 881 firstArgCand->env.apply(argType); 882 // strip references 883 // xxx - is this correct? 884 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base; 885 886 // convert 1-tuple to plain type 887 if (auto tuple = argType.as<ast::TupleType>()) { 888 if (tuple->size() == 1) { 889 argType = tuple->types[0]; 890 } 891 } 892 893 // if argType is an unbound type parameter, all special functions need to be searched. 894 if (isUnboundType(argType)) { 895 funcFinder.otypeKeys.clear(); 896 break; 897 } 898 899 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer); 900 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type)); 901 } 902 } 903 } 904 // if candidates are already produced, do not fail 905 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates? 906 // this means there exists ctor/assign functions with a tuple as first parameter. 907 ResolvMode mode = { 908 true, // adjust 909 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name 910 selfFinder.candidates.empty() // failfast if other options are not found 911 }; 912 funcFinder.find( untypedExpr->func, mode ); 913 // short-circuit if no candidates 914 // if ( funcFinder.candidates.empty() ) return; 915 916 reason.code = NoMatch; 845 917 846 918 // find function operators … … 877 949 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 878 950 CandidateRef newFunc{ new Candidate{ *func } }; 879 newFunc->expr = 951 newFunc->expr = 880 952 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 881 953 makeFunctionCandidates( newFunc, function, argExpansions, found ); 882 954 } 883 } else if ( 884 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 955 } else if ( 956 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 885 957 ) { 886 if ( const ast::EqvClass * clz = func->env.lookup( inst->name) ) {958 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 887 959 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 888 960 CandidateRef newFunc{ new Candidate{ *func } }; 889 newFunc->expr = 961 newFunc->expr = 890 962 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 891 963 makeFunctionCandidates( newFunc, function, argExpansions, found ); … … 901 973 std::vector< ExplodedArg > funcE; 902 974 funcE.reserve( funcFinder.candidates.size() ); 903 for ( const CandidateRef & func : funcFinder ) { 975 for ( const CandidateRef & func : funcFinder ) { 904 976 funcE.emplace_back( *func, symtab ); 905 977 } … … 913 985 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 914 986 CandidateRef newOp{ new Candidate{ *op} }; 915 newOp->expr = 987 newOp->expr = 916 988 referenceToRvalueConversion( newOp->expr, newOp->cost ); 917 989 makeFunctionCandidates( newOp, function, argExpansions, found ); … … 922 994 } 923 995 924 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 996 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 925 997 // candidates 926 998 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } … … 934 1006 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 935 1007 auto function = pointer->base.strict_as< ast::FunctionType >(); 936 1008 937 1009 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 938 1010 std::cerr << "parameters are:" << std::endl; … … 957 1029 promoteCvtCost( winners ); 958 1030 959 // function may return a struct/union value, in which case we need to add candidates 960 // for implicit conversions to each of the anonymous members, which must happen after 1031 // function may return a struct/union value, in which case we need to add candidates 1032 // for implicit conversions to each of the anonymous members, which must happen after 961 1033 // `findMinCost`, since anon conversions are never the cheapest 962 1034 for ( const CandidateRef & c : winners ) { … … 966 1038 967 1039 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 968 // If resolution is unsuccessful with a target type, try again without, since it 1040 // If resolution is unsuccessful with a target type, try again without, since it 969 1041 // will sometimes succeed when it wouldn't with a target type binding. 970 1042 // For example: … … 983 1055 /// true if expression is an lvalue 984 1056 static bool isLvalue( const ast::Expr * x ) { 985 return x->result && ( x-> result->is_lvalue() || x->result.as< ast::ReferenceType >() );1057 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 986 1058 } 987 1059 … … 989 1061 CandidateFinder finder{ symtab, tenv }; 990 1062 finder.find( addressExpr->arg ); 1063 1064 if( finder.candidates.empty() ) return; 1065 1066 reason.code = NoMatch; 1067 991 1068 for ( CandidateRef & r : finder.candidates ) { 992 1069 if ( ! isLvalue( r->expr ) ) continue; … … 1003 1080 assert( toType ); 1004 1081 toType = resolveTypeof( toType, symtab ); 1005 toType = SymTab::validateType( castExpr->location, toType, symtab );1082 // toType = SymTab::validateType( castExpr->location, toType, symtab ); 1006 1083 toType = adjustExprType( toType, tenv, symtab ); 1007 1084 1008 1085 CandidateFinder finder{ symtab, tenv, toType }; 1009 1086 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1087 1088 if( !finder.candidates.empty() ) reason.code = NoMatch; 1010 1089 1011 1090 CandidateList matches; … … 1016 1095 cand->env.extractOpenVars( open ); 1017 1096 1018 // It is possible that a cast can throw away some values in a multiply-valued 1019 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1020 // subexpression results that are cast directly. The candidate is invalid if it 1097 // It is possible that a cast can throw away some values in a multiply-valued 1098 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1099 // subexpression results that are cast directly. The candidate is invalid if it 1021 1100 // has fewer results than there are types to cast to. 1022 1101 int discardedValues = cand->expr->result->size() - toType->size(); … … 1025 1104 // unification run for side-effects 1026 1105 unify( toType, cand->expr->result, cand->env, need, have, open, symtab ); 1027 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env ); 1106 Cost thisCost = 1107 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast) 1108 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ) 1109 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ); 1110 1028 1111 PRINT( 1029 1112 std::cerr << "working on cast with result: " << toType << std::endl; … … 1037 1120 // count one safe conversion for each value that is thrown away 1038 1121 thisCost.incSafe( discardedValues ); 1039 CandidateRef newCand = std::make_shared<Candidate>( 1040 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1041 copy( cand->env ), move( open ), move( need ), cand->cost, 1122 CandidateRef newCand = std::make_shared<Candidate>( 1123 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1124 copy( cand->env ), move( open ), move( need ), cand->cost, 1042 1125 cand->cost + thisCost ); 1043 1126 inferParameters( newCand, matches ); … … 1057 1140 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1058 1141 for ( CandidateRef & r : finder.candidates ) { 1059 addCandidate( 1060 *r, 1142 addCandidate( 1143 *r, 1061 1144 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1062 1145 } 1146 } 1147 1148 void postvisit( const ast::KeywordCastExpr * castExpr ) { 1149 const auto & loc = castExpr->location; 1150 assertf( castExpr->result, "Cast target should have been set in Validate." ); 1151 auto ref = castExpr->result.strict_as<ast::ReferenceType>(); 1152 auto inst = ref->base.strict_as<ast::StructInstType>(); 1153 auto target = inst->base.get(); 1154 1155 CandidateFinder finder{ symtab, tenv }; 1156 1157 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) { 1158 for(auto & cand : found) { 1159 const ast::Type * expr = cand->expr->result.get(); 1160 if(expect_ref) { 1161 auto res = dynamic_cast<const ast::ReferenceType*>(expr); 1162 if(!res) { continue; } 1163 expr = res->base.get(); 1164 } 1165 1166 if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) { 1167 auto td = cand->env.lookup(*insttype); 1168 if(!td) { continue; } 1169 expr = td->bound.get(); 1170 } 1171 1172 if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) { 1173 if(base->base == target) { 1174 candidates.push_back( std::move(cand) ); 1175 reason.code = NoReason; 1176 } 1177 } 1178 } 1179 }; 1180 1181 try { 1182 // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd 1183 // Clone is purely for memory management 1184 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) }; 1185 1186 // don't prune here, since it's guaranteed all alternatives will have the same type 1187 finder.find( tech1.get(), ResolvMode::withoutPrune() ); 1188 pick_alternatives(finder.candidates, false); 1189 1190 return; 1191 } catch(SemanticErrorException & ) {} 1192 1193 // Fallback : turn (thread&)X into ($thread&)get_thread(X) 1194 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) }; 1195 // don't prune here, since it's guaranteed all alternatives will have the same type 1196 finder.find( fallback.get(), ResolvMode::withoutPrune() ); 1197 1198 pick_alternatives(finder.candidates, true); 1199 1200 // Whatever happens here, we have no more fallbacks 1063 1201 } 1064 1202 … … 1067 1205 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1068 1206 for ( CandidateRef & agg : aggFinder.candidates ) { 1069 // it's okay for the aggregate expression to have reference type -- cast it to the 1207 // it's okay for the aggregate expression to have reference type -- cast it to the 1070 1208 // base type to treat the aggregate as the referenced value 1071 1209 Cost addedCost = Cost::zero; … … 1074 1212 // find member of the given type 1075 1213 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1076 addAggMembers( 1214 addAggMembers( 1077 1215 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1078 1216 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1079 addAggMembers( 1217 addAggMembers( 1080 1218 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1081 1219 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1090 1228 1091 1229 void postvisit( const ast::NameExpr * nameExpr ) { 1092 std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name ); 1230 std::vector< ast::SymbolTable::IdData > declList; 1231 if (!selfFinder.otypeKeys.empty()) { 1232 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 1233 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str()); 1234 1235 for (auto & otypeKey: selfFinder.otypeKeys) { 1236 auto result = symtab.specialLookupId(kind, otypeKey); 1237 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end())); 1238 } 1239 } 1240 else { 1241 declList = symtab.lookupId( nameExpr->name ); 1242 } 1093 1243 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1244 1245 if( declList.empty() ) return; 1246 1247 reason.code = NoMatch; 1248 1094 1249 for ( auto & data : declList ) { 1095 1250 Cost cost = Cost::zero; … … 1097 1252 1098 1253 CandidateRef newCand = std::make_shared<Candidate>( 1099 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1254 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1100 1255 cost ); 1101 1256 PRINT( … … 1107 1262 std::cerr << std::endl; 1108 1263 ) 1109 newCand->expr = ast::mutate_field( 1110 newCand->expr.get(), &ast::Expr::result, 1264 newCand->expr = ast::mutate_field( 1265 newCand->expr.get(), &ast::Expr::result, 1111 1266 renameTyVars( newCand->expr->result ) ); 1112 // add anonymous member interpretations whenever an aggregate value type is seen 1267 // add anonymous member interpretations whenever an aggregate value type is seen 1113 1268 // as a name expression 1114 1269 addAnonConversions( newCand ); … … 1120 1275 // not sufficient to just pass `variableExpr` here, type might have changed since 1121 1276 // creation 1122 addCandidate( 1277 addCandidate( 1123 1278 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1124 1279 } … … 1130 1285 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1131 1286 if ( sizeofExpr->type ) { 1132 addCandidate( 1133 new ast::SizeofExpr{ 1134 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1287 addCandidate( 1288 new ast::SizeofExpr{ 1289 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1135 1290 tenv ); 1136 1291 } else { … … 1141 1296 CandidateList winners = findMinCost( finder.candidates ); 1142 1297 if ( winners.size() != 1 ) { 1143 SemanticError( 1298 SemanticError( 1144 1299 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1145 1300 } … … 1154 1309 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1155 1310 if ( alignofExpr->type ) { 1156 addCandidate( 1157 new ast::AlignofExpr{ 1158 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1311 addCandidate( 1312 new ast::AlignofExpr{ 1313 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1159 1314 tenv ); 1160 1315 } else { … … 1165 1320 CandidateList winners = findMinCost( finder.candidates ); 1166 1321 if ( winners.size() != 1 ) { 1167 SemanticError( 1322 SemanticError( 1168 1323 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1169 1324 } … … 1172 1327 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1173 1328 choice->cost = Cost::zero; 1174 addCandidate( 1329 addCandidate( 1175 1330 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1176 1331 } … … 1178 1333 1179 1334 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) { 1180 const ast:: ReferenceToType * aggInst;1335 const ast::BaseInstType * aggInst; 1181 1336 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ; 1182 1337 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ; … … 1185 1340 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1186 1341 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1187 addCandidate( 1342 addCandidate( 1188 1343 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1189 1344 } … … 1206 1361 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1207 1362 if ( finder2.candidates.empty() ) return; 1363 1364 reason.code = NoMatch; 1208 1365 1209 1366 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1218 1375 1219 1376 addCandidate( 1220 new ast::LogicalExpr{ 1377 new ast::LogicalExpr{ 1221 1378 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1222 1379 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1240 1397 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1241 1398 if ( finder3.candidates.empty() ) return; 1399 1400 reason.code = NoMatch; 1242 1401 1243 1402 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1256 1415 ast::AssertionSet have; 1257 1416 1258 // unify true and false results, then infer parameters to produce new 1417 // unify true and false results, then infer parameters to produce new 1259 1418 // candidates 1260 1419 ast::ptr< ast::Type > common; 1261 if ( 1262 unify( 1263 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1264 common ) 1420 if ( 1421 unify( 1422 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1423 common ) 1265 1424 ) { 1266 1425 // generate typed expression 1267 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1426 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1268 1427 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1269 1428 newExpr->result = common ? common : r2->expr->result; 1270 1429 // convert both options to result type 1271 1430 Cost cost = r1->cost + r2->cost + r3->cost; 1272 newExpr->arg2 = computeExpressionConversionCost( 1431 newExpr->arg2 = computeExpressionConversionCost( 1273 1432 newExpr->arg2, newExpr->result, symtab, env, cost ); 1274 1433 newExpr->arg3 = computeExpressionConversionCost( … … 1287 1446 ast::TypeEnvironment env{ tenv }; 1288 1447 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1289 1448 1290 1449 CandidateFinder finder2{ symtab, env }; 1291 1450 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1317 1476 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1318 1477 if ( finder2.candidates.empty() ) return; 1478 1479 reason.code = NoMatch; 1319 1480 1320 1481 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1330 1491 1331 1492 ast::ptr< ast::Type > common; 1332 if ( 1333 unify( 1334 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1335 common ) 1493 if ( 1494 unify( 1495 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1496 common ) 1336 1497 ) { 1337 1498 // generate new expression 1338 ast::RangeExpr * newExpr = 1499 ast::RangeExpr * newExpr = 1339 1500 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1340 1501 newExpr->result = common ? common : r1->expr->result; 1341 1502 // add candidate 1342 1503 CandidateRef newCand = std::make_shared<Candidate>( 1343 newExpr, move( env ), move( open ), move( need ), 1504 newExpr, move( env ), move( open ), move( need ), 1344 1505 r1->cost + r2->cost ); 1345 1506 inferParameters( newCand, candidates ); … … 1350 1511 1351 1512 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1352 std::vector< CandidateFinder > subCandidates = 1513 std::vector< CandidateFinder > subCandidates = 1353 1514 selfFinder.findSubExprs( tupleExpr->exprs ); 1354 1515 std::vector< CandidateList > possibilities; … … 1370 1531 1371 1532 addCandidate( 1372 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1533 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1373 1534 move( env ), move( open ), move( need ), sumCost( subs ) ); 1374 1535 } … … 1410 1571 // calculate target type 1411 1572 const ast::Type * toType = resolveTypeof( initAlt.type, symtab ); 1412 toType = SymTab::validateType( initExpr->location, toType, symtab );1573 // toType = SymTab::validateType( initExpr->location, toType, symtab ); 1413 1574 toType = adjustExprType( toType, tenv, symtab ); 1414 // The call to find must occur inside this loop, otherwise polymorphic return 1415 // types are not bound to the initialization type, since return type variables are 1416 // only open for the duration of resolving the UntypedExpr. 1575 // The call to find must occur inside this loop, otherwise polymorphic return 1576 // types are not bound to the initialization type, since return type variables are 1577 // only open for the duration of resolving the UntypedExpr. 1417 1578 CandidateFinder finder{ symtab, tenv, toType }; 1418 1579 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1419 1580 for ( CandidateRef & cand : finder.candidates ) { 1581 if(reason.code == NotFound) reason.code = NoMatch; 1582 1420 1583 ast::TypeEnvironment env{ cand->env }; 1421 1584 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; … … 1426 1589 ) 1427 1590 1428 // It is possible that a cast can throw away some values in a multiply-valued 1429 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1430 // the subexpression results that are cast directly. The candidate is invalid 1591 // It is possible that a cast can throw away some values in a multiply-valued 1592 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1593 // the subexpression results that are cast directly. The candidate is invalid 1431 1594 // if it has fewer results than there are types to cast to. 1432 1595 int discardedValues = cand->expr->result->size() - toType->size(); … … 1434 1597 1435 1598 // unification run for side-effects 1436 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1437 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1438 1599 bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab ); 1600 (void) canUnify; 1601 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1602 symtab, env ); 1603 PRINT( 1604 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1605 symtab, env ); 1606 std::cerr << "Considering initialization:"; 1607 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl; 1608 std::cerr << std::endl << " TO: " << toType << std::endl; 1609 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed"); 1610 std::cerr << std::endl << " Legacy cost " << legacyCost; 1611 std::cerr << std::endl << " New cost " << thisCost; 1612 std::cerr << std::endl; 1613 ) 1439 1614 if ( thisCost != Cost::infinity ) { 1440 1615 // count one safe conversion for each value that is thrown away 1441 1616 thisCost.incSafe( discardedValues ); 1442 CandidateRef newCand = std::make_shared<Candidate>( 1443 new ast::InitExpr{ 1444 initExpr->location, restructureCast( cand->expr, toType ), 1445 initAlt.designation }, 1446 copy( cand->env), move( open ), move( need ), cand->cost, thisCost );1617 CandidateRef newCand = std::make_shared<Candidate>( 1618 new ast::InitExpr{ 1619 initExpr->location, restructureCast( cand->expr, toType ), 1620 initAlt.designation }, 1621 move(env), move( open ), move( need ), cand->cost, thisCost ); 1447 1622 inferParameters( newCand, matches ); 1448 1623 } 1449 1624 } 1625 1450 1626 } 1451 1627 … … 1469 1645 }; 1470 1646 1471 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1647 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder"); 1648 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1472 1649 /// return type. Skips ambiguous candidates. 1473 CandidateList pruneCandidates( CandidateList & candidates ) { 1474 struct PruneStruct { 1475 CandidateRef candidate; 1476 bool ambiguous; 1477 1478 PruneStruct() = default; 1479 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1480 }; 1481 1482 // find lowest-cost candidate for each type 1483 std::unordered_map< std::string, PruneStruct > selected; 1484 for ( CandidateRef & candidate : candidates ) { 1485 std::string mangleName; 1650 1651 } // anonymous namespace 1652 1653 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) { 1654 struct PruneStruct { 1655 CandidateRef candidate; 1656 bool ambiguous; 1657 1658 PruneStruct() = default; 1659 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1660 }; 1661 1662 // find lowest-cost candidate for each type 1663 std::unordered_map< std::string, PruneStruct > selected; 1664 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found 1665 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;}); 1666 for ( CandidateRef & candidate : candidates ) { 1667 std::string mangleName; 1668 { 1669 ast::ptr< ast::Type > newType = candidate->expr->result; 1670 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1671 candidate->env.apply( newType ); 1672 mangleName = Mangle::mangle( newType ); 1673 } 1674 1675 auto found = selected.find( mangleName ); 1676 if (found != selected.end() && found->second.candidate->cost < candidate->cost) { 1677 PRINT( 1678 std::cerr << "cost " << candidate->cost << " loses to " 1679 << found->second.candidate->cost << std::endl; 1680 ) 1681 continue; 1682 } 1683 1684 // xxx - when do satisfyAssertions produce more than 1 result? 1685 // this should only happen when initial result type contains 1686 // unbound type parameters, then it should never be pruned by 1687 // the previous step, since renameTyVars guarantees the mangled name 1688 // is unique. 1689 CandidateList satisfied; 1690 bool needRecomputeKey = false; 1691 if (candidate->need.empty()) { 1692 satisfied.emplace_back(candidate); 1693 } 1694 else { 1695 satisfyAssertions(candidate, localSyms, satisfied, errors); 1696 needRecomputeKey = true; 1697 } 1698 1699 for (auto & newCand : satisfied) { 1700 // recomputes type key, if satisfyAssertions changed it 1701 if (needRecomputeKey) 1486 1702 { 1487 ast::ptr< ast::Type > newType = candidate->expr->result; 1488 candidate->env.apply( newType ); 1703 ast::ptr< ast::Type > newType = newCand->expr->result; 1704 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get()); 1705 newCand->env.apply( newType ); 1489 1706 mangleName = Mangle::mangle( newType ); 1490 1707 } 1491 1492 1708 auto found = selected.find( mangleName ); 1493 1709 if ( found != selected.end() ) { 1494 if ( candidate->cost < found->second.candidate->cost ) {1710 if ( newCand->cost < found->second.candidate->cost ) { 1495 1711 PRINT( 1496 std::cerr << "cost " << candidate->cost << " beats "1712 std::cerr << "cost " << newCand->cost << " beats " 1497 1713 << found->second.candidate->cost << std::endl; 1498 1714 ) 1499 1715 1500 found->second = PruneStruct{ candidate};1501 } else if ( candidate->cost == found->second.candidate->cost ) {1502 // if one of the candidates contains a deleted identifier, can pick the other, 1503 // since deleted expressions should not be ambiguous if there is another option 1716 found->second = PruneStruct{ newCand }; 1717 } else if ( newCand->cost == found->second.candidate->cost ) { 1718 // if one of the candidates contains a deleted identifier, can pick the other, 1719 // since deleted expressions should not be ambiguous if there is another option 1504 1720 // that is at least as good 1505 if ( findDeletedExpr( candidate->expr ) ) {1721 if ( findDeletedExpr( newCand->expr ) ) { 1506 1722 // do nothing 1507 1723 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 1508 1724 } else if ( findDeletedExpr( found->second.candidate->expr ) ) { 1509 1725 PRINT( std::cerr << "current is deleted" << std::endl; ) 1510 found->second = PruneStruct{ candidate};1726 found->second = PruneStruct{ newCand }; 1511 1727 } else { 1512 1728 PRINT( std::cerr << "marking ambiguous" << std::endl; ) 1513 1729 found->second.ambiguous = true; 1514 1730 } 1515 } else { 1731 } else { 1732 // xxx - can satisfyAssertions increase the cost? 1516 1733 PRINT( 1517 std::cerr << "cost " << candidate->cost << " loses to "1734 std::cerr << "cost " << newCand->cost << " loses to " 1518 1735 << found->second.candidate->cost << std::endl; 1519 ) 1736 ) 1520 1737 } 1521 1738 } else { 1522 selected.emplace_hint( found, mangleName, candidate ); 1523 } 1524 } 1525 1526 // report unambiguous min-cost candidates 1527 CandidateList out; 1528 for ( auto & target : selected ) { 1529 if ( target.second.ambiguous ) continue; 1530 1531 CandidateRef cand = target.second.candidate; 1532 1533 ast::ptr< ast::Type > newResult = cand->expr->result; 1534 cand->env.applyFree( newResult ); 1535 cand->expr = ast::mutate_field( 1536 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1537 1538 out.emplace_back( cand ); 1539 } 1540 return out; 1739 selected.emplace_hint( found, mangleName, newCand ); 1740 } 1741 } 1541 1742 } 1542 1743 1543 } // anonymous namespace 1744 // report unambiguous min-cost candidates 1745 // CandidateList out; 1746 for ( auto & target : selected ) { 1747 if ( target.second.ambiguous ) continue; 1748 1749 CandidateRef cand = target.second.candidate; 1750 1751 ast::ptr< ast::Type > newResult = cand->expr->result; 1752 cand->env.applyFree( newResult ); 1753 cand->expr = ast::mutate_field( 1754 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1755 1756 out.emplace_back( cand ); 1757 } 1758 // if everything is lost in satisfyAssertions, report the error 1759 return !selected.empty(); 1760 } 1544 1761 1545 1762 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) { … … 1549 1766 1550 1767 if ( mode.failFast && candidates.empty() ) { 1551 SemanticError( expr, "No reasonable alternatives for expression " ); 1768 switch(finder.core.reason.code) { 1769 case Finder::NotFound: 1770 { SemanticError( expr, "No alternatives for expression " ); break; } 1771 case Finder::NoMatch: 1772 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1773 case Finder::ArgsToFew: 1774 case Finder::ArgsToMany: 1775 case Finder::RetsToFew: 1776 case Finder::RetsToMany: 1777 case Finder::NoReason: 1778 default: 1779 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1780 } 1552 1781 } 1553 1782 1783 /* 1554 1784 if ( mode.satisfyAssns || mode.prune ) { 1555 1785 // trim candidates to just those where the assertions are satisfiable … … 1558 1788 std::vector< std::string > errors; 1559 1789 for ( CandidateRef & candidate : candidates ) { 1560 satisfyAssertions( candidate, symtab, satisfied, errors );1790 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1561 1791 } 1562 1792 … … 1574 1804 candidates = move( satisfied ); 1575 1805 } 1806 */ 1576 1807 1577 1808 if ( mode.prune ) { … … 1582 1813 ) 1583 1814 1584 CandidateList pruned = pruneCandidates( candidates ); 1585 1815 CandidateList pruned; 1816 std::vector<std::string> errors; 1817 bool found = pruneCandidates( candidates, pruned, errors ); 1818 1586 1819 if ( mode.failFast && pruned.empty() ) { 1587 1820 std::ostringstream stream; 1588 CandidateList winners = findMinCost( candidates ); 1589 stream << "Cannot choose between " << winners.size() << " alternatives for " 1590 "expression\n"; 1591 ast::print( stream, expr ); 1592 stream << " Alternatives are:\n"; 1593 print( stream, winners, 1 ); 1594 SemanticError( expr->location, stream.str() ); 1821 if (found) { 1822 CandidateList winners = findMinCost( candidates ); 1823 stream << "Cannot choose between " << winners.size() << " alternatives for " 1824 "expression\n"; 1825 ast::print( stream, expr ); 1826 stream << " Alternatives are:\n"; 1827 print( stream, winners, 1 ); 1828 SemanticError( expr->location, stream.str() ); 1829 } 1830 else { 1831 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1832 for ( const auto& err : errors ) { 1833 stream << err; 1834 } 1835 SemanticError( expr->location, stream.str() ); 1836 } 1595 1837 } 1596 1838 … … 1602 1844 ) 1603 1845 PRINT( 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1846 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1605 1847 << std::endl; 1606 1848 ) 1607 1849 } 1608 1850 1609 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1851 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1610 1852 // adjusted 1611 1853 if ( mode.adjust ) { 1612 1854 for ( CandidateRef & r : candidates ) { 1613 r->expr = ast::mutate_field( 1614 r->expr.get(), &ast::Expr::result, 1615 adjustExprType( r->expr->result, r->env, symtab) );1855 r->expr = ast::mutate_field( 1856 r->expr.get(), &ast::Expr::result, 1857 adjustExprType( r->expr->result, r->env, localSyms ) ); 1616 1858 } 1617 1859 } … … 1625 1867 } 1626 1868 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1869 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1870 const std::vector< ast::ptr< ast::Expr > > & xs 1629 1871 ) { 1630 1872 std::vector< CandidateFinder > out; 1631 1873 1632 1874 for ( const auto & x : xs ) { 1633 out.emplace_back( symtab, env );1875 out.emplace_back( localSyms, env ); 1634 1876 out.back().find( x, ResolvMode::withAdjustment() ); 1635 1877 1636 1878 PRINT( 1637 1879 std::cerr << "findSubExprs" << std::endl; -
src/ResolvExpr/CandidateFinder.hpp
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 9:51:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 28 28 struct CandidateFinder { 29 29 CandidateList candidates; ///< List of candidate resolutions 30 const ast::SymbolTable & symtab; ///< Symbol table to lookup candidates30 const ast::SymbolTable & localSyms; ///< Symbol table to lookup candidates 31 31 const ast::TypeEnvironment & env; ///< Substitutions performed in this resolution 32 32 ast::ptr< ast::Type > targetType; ///< Target type for resolution 33 std::set< std::string > otypeKeys; /// different type may map to same key 33 34 34 CandidateFinder( 35 const ast::SymbolTable & sym tab, const ast::TypeEnvironment & env,35 CandidateFinder( 36 const ast::SymbolTable & syms, const ast::TypeEnvironment & env, 36 37 const ast::Type * tt = nullptr ) 37 : candidates(), symtab( symtab), env( env ), targetType( tt ) {}38 : candidates(), localSyms( syms ), env( env ), targetType( tt ) {} 38 39 39 40 /// Fill candidates with feasible resolutions for `expr` 40 41 void find( const ast::Expr * expr, ResolvMode mode = {} ); 42 bool pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ); 41 43 42 44 /// Runs new candidate finder on each element in xs, returning the list of finders … … 49 51 iterator begin() { return candidates.begin(); } 50 52 const_iterator begin() const { return candidates.begin(); } 51 53 52 54 iterator end() { return candidates.end(); } 53 55 const_iterator end() const { return candidates.end(); } … … 55 57 56 58 /// Computes conversion cost between two types 57 Cost computeConversionCost( 58 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,59 const ast:: TypeEnvironment & env );59 Cost computeConversionCost( 60 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 61 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 60 62 61 63 } // namespace ResolvExpr -
src/ResolvExpr/CastCost.cc
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 06:57:43 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:12:00 201913 // Update Count : 812 // Last Modified On : Tue Oct 4 15:00:00 2019 13 // Update Count : 9 14 14 // 15 15 … … 142 142 143 143 CastCost_new( 144 const ast::Type * dst, const ast::SymbolTable & symtab,144 const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 145 145 const ast::TypeEnvironment & env, CostCalculation costFunc ) 146 : ConversionCost_new( dst, s ymtab, env, costFunc ) {}146 : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {} 147 147 148 148 void postvisit( const ast::BasicType * basicType ) { … … 152 152 cost = Cost::unsafe; 153 153 } else { 154 cost = conversionCost( basicType, dst, s ymtab, env );154 cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env ); 155 155 } 156 156 } … … 165 165 } else { 166 166 ast::TypeEnvironment newEnv{ env }; 167 if ( auto wParams = pointerType->base.as< ast:: ParameterizedType >() ) {167 if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) { 168 168 newEnv.add( wParams->forall ); 169 169 } … … 183 183 } 184 184 }; 185 186 #warning For overload resolution between the two versions. 187 int localPtrsCastable(const ast::Type * t1, const ast::Type * t2, 188 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) { 189 return ptrsCastable( t1, t2, symtab, env ); 190 } 191 Cost localCastCost( 192 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 193 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 194 ) { return castCost( src, dst, srcIsLvalue, symtab, env ); } 185 195 } // anonymous namespace 186 196 197 198 187 199 Cost castCost( 188 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,189 const ast:: TypeEnvironment & env200 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 201 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 190 202 ) { 191 203 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 192 if ( const ast::EqvClass * eqvClass = env.lookup( typeInst->name) ) {204 if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) { 193 205 // check cast cost against bound type, if present 194 206 if ( eqvClass->bound ) { 195 return castCost( src, eqvClass->bound, s ymtab, env );207 return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env ); 196 208 } else { 197 209 return Cost::infinity; … … 201 213 auto type = strict_dynamic_cast< const ast::TypeDecl * >( named ); 202 214 if ( type->base ) { 203 return castCost( src, type->base, s ymtab, env ) + Cost::safe;215 return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe; 204 216 } 205 217 } … … 224 236 #warning cast on ptrsCastable artifact of having two functions, remove when port done 225 237 return convertToReferenceCost( 226 src, refType, symtab, env, 227 ( int (*)( 228 const ast::Type *, const ast::Type *, const ast::SymbolTable &, 229 const ast::TypeEnvironment & ) 230 ) ptrsCastable ); 238 src, refType, srcIsLvalue, symtab, env, localPtrsCastable ); 231 239 } else { 232 240 #warning cast on castCost artifact of having two functions, remove when port done 233 ast::Pass< CastCost_new > converter{ 234 dst, symtab, env, 235 ( Cost (*)( 236 const ast::Type *, const ast::Type *, const ast::SymbolTable &, 237 const ast::TypeEnvironment & ) 238 ) castCost }; 241 ast::Pass< CastCost_new > converter( 242 dst, srcIsLvalue, symtab, env, localCastCost ); 239 243 src->accept( converter ); 240 return converter. pass.cost;244 return converter.core.cost; 241 245 } 242 246 } -
src/ResolvExpr/CommonType.cc
rbdfc032 reef8dfb 666 666 const ast::OpenVarSet & open; 667 667 public: 668 static size_t traceId; 668 669 ast::ptr< ast::Type > result; 669 670 … … 712 713 const ast::Type * base = oPtr->base; 713 714 if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) { 714 auto entry = open.find( var->name);715 auto entry = open.find( *var ); 715 716 if ( entry != open.end() ) { 716 717 ast::AssertionSet need, have; … … 893 894 }; 894 895 896 // size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new"); 895 897 namespace { 896 898 ast::ptr< ast::Type > handleReference( … … 939 941 ast::ptr< ast::Type > result; 940 942 const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >(); 941 const ast::ReferenceType * ref2 = type 1.as< ast::ReferenceType >();943 const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >(); 942 944 943 945 if ( depth1 > depth2 ) { … … 966 968 ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open }; 967 969 type1->accept( visitor ); 968 ast::ptr< ast::Type > result = visitor. pass.result;970 ast::ptr< ast::Type > result = visitor.core.result; 969 971 970 972 // handling for opaque type declarations (?) -
src/ResolvExpr/ConversionCost.cc
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 07:06:19 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Aug 12 10:21:00 201913 // Update Count : 2 712 // Last Modified On : Wed Jul 29 16:11:00 2020 13 // Update Count : 28 14 14 // 15 15 … … 392 392 void ConversionCost::postvisit( const FunctionType * ) {} 393 393 394 void ConversionCost::postvisit( const StructInstType * inst ) {395 if ( const StructInstType * destAsInst = dynamic_cast< const StructInstType * >( dest ) ) {396 if ( inst->name == destAsInst->name ) {397 cost = Cost::zero;398 } // if399 } // if400 }401 402 void ConversionCost::postvisit( const UnionInstType * inst ) {403 if ( const UnionInstType * destAsInst = dynamic_cast< const UnionInstType * >( dest ) ) {404 if ( inst->name == destAsInst->name ) {405 cost = Cost::zero;406 } // if407 } // if408 }409 410 394 void ConversionCost::postvisit( const EnumInstType * ) { 411 395 static Type::Qualifiers q; … … 497 481 } 498 482 499 static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 500 const ast::SymbolTable &, const ast::TypeEnvironment & env ) {501 return ptrsAssignable( t1, t2, env );502 } 503 504 // TODO: This is used for overload resolution. It might be able to be dropped once the old system 505 // is removed. 506 static Cost localConversionCost( 507 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,508 const ast::TypeEnvironment & env509 ) { return conversionCost( src, dst, symtab, env );}483 namespace { 484 # warning For overload resolution between the two versions. 485 int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 486 const ast::SymbolTable &, const ast::TypeEnvironment & env ) { 487 return ptrsAssignable( t1, t2, env ); 488 } 489 Cost localConversionCost( 490 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 491 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 492 ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); } 493 } 510 494 511 495 Cost conversionCost( 512 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,513 const ast:: TypeEnvironment & env496 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 497 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 514 498 ) { 515 499 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 516 if ( const ast::EqvClass * eqv = env.lookup( inst->name) ) {500 if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) { 517 501 if ( eqv->bound ) { 518 return conversionCost(src, eqv->bound, s ymtab, env );502 return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env ); 519 503 } else { 520 504 return Cost::infinity; … … 524 508 assertf( type, "Unexpected typedef." ); 525 509 if ( type->base ) { 526 return conversionCost( src, type->base, s ymtab, env ) + Cost::safe;510 return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe; 527 511 } 528 512 } … … 534 518 } else if ( const ast::ReferenceType * refType = 535 519 dynamic_cast< const ast::ReferenceType * >( dst ) ) { 536 return convertToReferenceCost( src, refType, s ymtab, env, localPtrsAssignable );520 return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable ); 537 521 } else { 538 ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost ); 539 src->accept( converter ); 540 return converter.pass.cost; 541 } 542 } 543 544 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, 522 return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost ); 523 } 524 } 525 526 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 545 527 int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 546 NumCostCalculation func ) {528 PtrsCalculation func ) { 547 529 if ( 0 < diff ) { 548 530 Cost cost = convertToReferenceCost( 549 strict_dynamic_cast< const ast::ReferenceType * >( src )->base, 550 dst, (diff - 1), symtab, env, func );531 strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst, 532 srcIsLvalue, (diff - 1), symtab, env, func ); 551 533 cost.incReference(); 552 534 return cost; … … 554 536 Cost cost = convertToReferenceCost( 555 537 src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base, 556 (diff + 1), symtab, env, func );538 srcIsLvalue, (diff + 1), symtab, env, func ); 557 539 cost.incReference(); 558 540 return cost; … … 579 561 } 580 562 } else { 581 ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost ); 582 src->accept( converter ); 583 return converter.pass.cost; 563 return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost ); 584 564 } 585 565 } else { … … 588 568 assert( dstAsRef ); 589 569 if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) { 590 if ( src ->is_lvalue()) {570 if ( srcIsLvalue ) { 591 571 if ( src->qualifiers == dstAsRef->base->qualifiers ) { 592 572 return Cost::reference; … … 607 587 608 588 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst, 609 610 NumCostCalculation func ) {589 bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 590 PtrsCalculation func ) { 611 591 int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth(); 612 return convertToReferenceCost( src, dst, s depth - ddepth, symtab, env, func );592 return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func ); 613 593 } 614 594 … … 667 647 assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) ); 668 648 669 cost = costCalc( refType->base, dst, s ymtab, env );649 cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env ); 670 650 if ( refType->base->qualifiers == dst->qualifiers ) { 671 651 cost.incReference(); … … 681 661 } 682 662 683 void ConversionCost_new::postvisit( const ast::StructInstType * structInstType ) {684 if ( const ast::StructInstType * dstAsInst =685 dynamic_cast< const ast::StructInstType * >( dst ) ) {686 if ( structInstType->name == dstAsInst->name ) {687 cost = Cost::zero;688 }689 }690 }691 692 void ConversionCost_new::postvisit( const ast::UnionInstType * unionInstType ) {693 if ( const ast::UnionInstType * dstAsInst =694 dynamic_cast< const ast::UnionInstType * >( dst ) ) {695 if ( unionInstType->name == dstAsInst->name ) {696 cost = Cost::zero;697 }698 }699 }700 701 663 void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) { 702 664 (void)enumInstType; 703 static const ast::BasicType integer( ast::BasicType::SignedInt );704 cost = costCalc( &integer, dst, symtab, env );665 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) }; 666 cost = costCalc( integer, dst, srcIsLvalue, symtab, env ); 705 667 if ( cost < Cost::unsafe ) { 706 668 cost.incSafe(); … … 713 675 714 676 void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) { 715 if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {716 cost = costCalc( eqv->bound, dst, s ymtab, env );677 if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) { 678 cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env ); 717 679 } else if ( const ast::TypeInstType * dstAsInst = 718 680 dynamic_cast< const ast::TypeInstType * >( dst ) ) { 719 if ( typeInstType->name == dstAsInst->name) {681 if ( *typeInstType == *dstAsInst ) { 720 682 cost = Cost::zero; 721 683 } … … 724 686 assertf( type, "Unexpected typedef."); 725 687 if ( type->base ) { 726 cost = costCalc( type->base, dst, s ymtab, env ) + Cost::safe;688 cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe; 727 689 } 728 690 } … … 737 699 auto dstEnd = dstAsTuple->types.end(); 738 700 while ( srcIt != srcEnd && dstIt != dstEnd ) { 739 Cost newCost = costCalc( * srcIt++, * dstIt++, s ymtab, env );701 Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env ); 740 702 if ( newCost == Cost::infinity ) { 741 703 return; … … 772 734 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 773 735 } 736 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 737 cost = Cost::zero; 738 // +1 for zero_t ->, +1 for disambiguation 739 cost.incSafe( maxIntCost + 2 ); 774 740 } 775 741 } … … 789 755 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 790 756 } 791 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 792 cost = Cost::zero; 793 cost.incSafe( maxIntCost + 2 ); 794 } 795 } 796 757 } 758 } 759 // size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost"); 797 760 798 761 } // namespace ResolvExpr -
src/ResolvExpr/ConversionCost.h
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 09:37:28 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Aug 8 16:13:00 201913 // Update Count : 612 // Last Modified On : Wed Jul 29 16:12:00 2020 13 // Update Count : 7 14 14 // 15 15 … … 51 51 void postvisit( const ReferenceType * refType ); 52 52 void postvisit( const FunctionType * functionType ); 53 void postvisit( const StructInstType * aggregateUseType );54 void postvisit( const UnionInstType * aggregateUseType );55 53 void postvisit( const EnumInstType * aggregateUseType ); 56 54 void postvisit( const TraitInstType * aggregateUseType ); … … 74 72 75 73 // Some function pointer types, differ in return type. 76 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, 74 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool, 77 75 const ast::SymbolTable &, const ast::TypeEnvironment &)>; 78 using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,76 using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *, 79 77 const ast::SymbolTable &, const ast::TypeEnvironment &)>; 80 78 … … 83 81 protected: 84 82 const ast::Type * dst; 83 bool srcIsLvalue; 85 84 const ast::SymbolTable & symtab; 86 85 const ast::TypeEnvironment & env; 87 86 CostCalculation costCalc; 88 87 public: 88 static size_t traceId; 89 89 Cost cost; 90 Cost result() { return cost; } 90 91 91 ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,92 ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 92 93 const ast::TypeEnvironment & env, CostCalculation costCalc ) : 93 dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity ) 94 dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ), 95 costCalc( costCalc ), cost( Cost::infinity ) 94 96 {} 95 97 … … 102 104 void postvisit( const ast::ReferenceType * refType ); 103 105 void postvisit( const ast::FunctionType * functionType ); 104 void postvisit( const ast::StructInstType * structInstType );105 void postvisit( const ast::UnionInstType * unionInstType );106 106 void postvisit( const ast::EnumInstType * enumInstType ); 107 107 void postvisit( const ast::TraitInstType * traitInstType ); … … 114 114 115 115 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest, 116 const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func ); 116 bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, 117 PtrsCalculation func ); 117 118 118 119 } // namespace ResolvExpr -
src/ResolvExpr/CurrentObject.cc
rbdfc032 reef8dfb 21 21 #include <string> // for string, operator<<, allocator 22 22 23 #include "AST/Copy.hpp" // for shallowCopy 23 24 #include "AST/Expr.hpp" // for InitAlternative 24 25 #include "AST/GenericSubstitution.hpp" // for genericSubstitution 25 26 #include "AST/Init.hpp" // for Designation 26 27 #include "AST/Node.hpp" // for readonly 28 #include "AST/Print.hpp" // for readonly 27 29 #include "AST/Type.hpp" 28 30 #include "Common/Indenter.h" // for Indenter, operator<< … … 592 594 class SimpleIterator final : public MemberIterator { 593 595 CodeLocation location; 594 readonly< Type >type = nullptr;596 const Type * type = nullptr; 595 597 public: 596 598 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {} 597 599 598 void setPosition( 599 std::deque< ptr< Expr > >::const_iterator begin, 600 void setPosition( 601 std::deque< ptr< Expr > >::const_iterator begin, 600 602 std::deque< ptr< Expr > >::const_iterator end 601 603 ) override { … … 628 630 class ArrayIterator final : public MemberIterator { 629 631 CodeLocation location; 630 readonly< ArrayType >array = nullptr;631 readonly< Type >base = nullptr;632 const ArrayType * array = nullptr; 633 const Type * base = nullptr; 632 634 size_t index = 0; 633 635 size_t size = 0; … … 637 639 auto res = eval(expr); 638 640 if ( ! res.second ) { 639 SemanticError( location, 641 SemanticError( location, 640 642 toString("Array designator must be a constant expression: ", expr ) ); 641 643 } … … 644 646 645 647 public: 646 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 648 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 647 649 : location( loc ), array( at ), base( at->base ) { 648 650 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) … … 655 657 656 658 void setPosition( const Expr * expr ) { 657 // need to permit integer-constant-expressions, including: integer constants, 658 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 // need to permit integer-constant-expressions, including: integer constants, 660 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 661 // cast expressions 660 662 if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 662 664 index = constExpr->intValue(); 663 665 } catch ( SemanticErrorException & ) { 664 SemanticError( expr, 666 SemanticError( expr, 665 667 "Constant expression of non-integral type in array designator: " ); 666 668 } 667 669 } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) { 668 670 setPosition( castExpr->arg ); 669 } else if ( 670 dynamic_cast< const SizeofExpr * >( expr ) 671 || dynamic_cast< const AlignofExpr * >( expr ) 671 } else if ( 672 dynamic_cast< const SizeofExpr * >( expr ) 673 || dynamic_cast< const AlignofExpr * >( expr ) 672 674 ) { 673 675 index = 0; 674 676 } else { 675 assertf( false, 677 assertf( false, 676 678 "bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 677 679 } 678 680 } 679 681 680 void setPosition( 681 std::deque< ptr< Expr > >::const_iterator begin, 682 void setPosition( 683 std::deque< ptr< Expr > >::const_iterator begin, 682 684 std::deque< ptr< Expr > >::const_iterator end 683 685 ) override { … … 758 760 } 759 761 760 AggregateIterator( 761 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 AggregateIterator( 763 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 764 const MemberList & ms ) 763 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 765 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 764 766 sub( genericSubstitution( i ) ) { 765 767 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) … … 768 770 769 771 public: 770 void setPosition( 771 std::deque< ptr< Expr > >::const_iterator begin, 772 void setPosition( 773 std::deque< ptr< Expr > >::const_iterator begin, 772 774 std::deque< ptr< Expr > >::const_iterator end 773 775 ) final { … … 786 788 return; 787 789 } 788 assertf( false, 790 assertf( false, 789 791 "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 790 792 } else { 791 assertf( false, 793 assertf( false, 792 794 "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() ); 793 795 } … … 803 805 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 804 806 // need to substitute for generic types so that casts are to concrete types 807 alt.type = shallowCopy(alt.type.get()); 805 808 PRINT( std::cerr << " type is: " << alt.type; ) 806 809 sub.apply( alt.type ); // also apply to designation?? … … 842 845 for ( InitAlternative & alt : ret ) { 843 846 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 844 alt.designation.get_and_mutate()->designators.emplace_front( 847 alt.designation.get_and_mutate()->designators.emplace_front( 845 848 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 846 849 } … … 897 900 class TupleIterator final : public AggregateIterator { 898 901 public: 899 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 900 : AggregateIterator( 901 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 903 : AggregateIterator( 904 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 905 ) {} 903 906 … … 920 923 921 924 MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) { 922 if ( auto aggr = dynamic_cast< const ReferenceToType * >( type ) ) {925 if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) { 923 926 if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) { 924 927 return new StructIterator{ loc, sit }; … … 926 929 return new UnionIterator{ loc, uit }; 927 930 } else { 928 assertf( 929 dynamic_cast< const EnumInstType * >( aggr )930 || dynamic_cast< const TypeInstType * >( aggr ),931 "Encountered unhandled ReferenceToType in createMemberIterator: %s",931 assertf( 932 dynamic_cast< const EnumInstType * >( type ) 933 || dynamic_cast< const TypeInstType * >( type ), 934 "Encountered unhandled BaseInstType in createMemberIterator: %s", 932 935 toString( type ).c_str() ); 933 936 return new SimpleIterator{ loc, type }; … … 949 952 using DesignatorChain = std::deque< ptr< Expr > >; 950 953 PRINT( std::cerr << "___findNext" << std::endl; ) 951 954 952 955 // find all the d's 953 956 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts; … … 962 965 DesignatorChain & d = *dit; 963 966 PRINT( std::cerr << "____actual: " << t << std::endl; ) 964 if ( auto refType = dynamic_cast< const ReferenceToType * >( t ) ) {967 if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) { 965 968 // concatenate identical field names 966 969 for ( const Decl * mem : refType->lookup( nexpr->name ) ) { … … 1013 1016 // set new designators 1014 1017 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 1015 Designation * actualDesignation = 1018 Designation * actualDesignation = 1016 1019 new Designation{ designation->location, DesignatorChain{d} }; 1017 1020 objStack.back()->setPosition( d ); // destroys d -
src/ResolvExpr/FindOpenVars.cc
rbdfc032 reef8dfb 112 112 // mark open/closed variables 113 113 if ( nextIsOpen ) { 114 for ( const ast::TypeDecl *decl : type->forall ) {115 open[ decl->name ] = ast::TypeDecl::Data{ decl};116 for ( const ast::DeclWithType * assert : decl->assertions ) {117 need[ assert ].isUsed = false;118 }114 for ( auto & decl : type->forall ) { 115 open[ *decl ] = ast::TypeDecl::Data{ decl->base }; 116 } 117 for ( auto & assert : type->assertions ) { 118 need[ assert ].isUsed = false; 119 119 } 120 120 } else { 121 for ( const ast::TypeDecl *decl : type->forall ) {122 closed[ decl->name ] = ast::TypeDecl::Data{ decl };123 for ( const ast::DeclWithType * assert : decl->assertions ) {124 have[ assert ].isUsed = false;125 }121 for ( auto & decl : type->forall ) { 122 closed[ *decl ] = ast::TypeDecl::Data{ decl->base }; 123 } 124 for ( auto & assert : type->assertions ) { 125 have[ assert ].isUsed = false; 126 126 } 127 127 } -
src/ResolvExpr/PolyCost.cc
rbdfc032 reef8dfb 58 58 59 59 // TODO: When the old PolyCost is torn out get rid of the _new suffix. 60 struct PolyCost_new { 60 class PolyCost_new { 61 const ast::SymbolTable &symtab; 62 public: 61 63 int result; 62 const ast::SymbolTable &symtab;63 64 const ast::TypeEnvironment &env_; 64 65 65 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :66 result( 0 ), symtab( symtab), env_( env ) {}66 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 67 : symtab( symtab ), result( 0 ), env_( env ) {} 67 68 68 69 void previsit( const ast::TypeInstType * type ) { 69 if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {70 if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) { 70 71 if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) { 71 72 if ( symtab.lookupType( otherType->name ) ) { … … 86 87 ast::Pass<PolyCost_new> costing( symtab, env ); 87 88 type->accept( costing ); 88 return costing. pass.result;89 return costing.core.result; 89 90 } 90 91 -
src/ResolvExpr/PtrsAssignable.cc
rbdfc032 reef8dfb 134 134 } 135 135 void postvisit( const ast::TypeInstType * inst ) { 136 if ( const ast::EqvClass * eqv = typeEnv.lookup( inst->name) ) {136 if ( const ast::EqvClass * eqv = typeEnv.lookup( *inst ) ) { 137 137 if ( eqv->bound ) { 138 138 // T * = S * for any S depends on the type bound to T … … 146 146 const ast::TypeEnvironment & env ) { 147 147 if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 148 if ( const ast::EqvClass * eqv = env.lookup( dstAsInst->name) ) {148 if ( const ast::EqvClass * eqv = env.lookup( *dstAsInst ) ) { 149 149 return ptrsAssignable( src, eqv->bound, env ); 150 150 } … … 155 155 ast::Pass<PtrsAssignable_new> visitor( dst, env ); 156 156 src->accept( visitor ); 157 return visitor. pass.result;157 return visitor.core.result; 158 158 } 159 159 -
src/ResolvExpr/PtrsCastable.cc
rbdfc032 reef8dfb 180 180 } 181 181 } 182 } else if ( const ast::EqvClass * eqvClass = env.lookup( inst->name) ) {182 } else if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) { 183 183 if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) { 184 184 return -1; … … 283 283 ) { 284 284 if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 285 if ( const ast::EqvClass * eqvClass = env.lookup( inst->name) ) {285 if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) { 286 286 return ptrsAssignable( src, eqvClass->bound, env ); 287 287 } … … 293 293 ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab }; 294 294 src->accept( ptrs ); 295 return ptrs. pass.result;295 return ptrs.core.result; 296 296 } 297 297 } -
src/ResolvExpr/RenameVars.cc
rbdfc032 reef8dfb 30 30 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 31 31 32 #include "AST/Copy.hpp" 33 32 34 namespace ResolvExpr { 33 35 … … 36 38 int level = 0; 37 39 int resetCount = 0; 40 41 int next_expr_id = 1; 42 int next_usage_id = 1; 38 43 ScopedMap< std::string, std::string > nameMap; 39 44 ScopedMap< std::string, ast::TypeInstType::TypeEnvKey > idMap; 40 45 public: 41 46 void reset() { … … 44 49 } 45 50 46 using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;47 48 51 void rename( TypeInstType * type ) { 49 mapConstIteratorit = nameMap.find( type->name );52 auto it = nameMap.find( type->name ); 50 53 if ( it != nameMap.end() ) { 51 54 type->name = it->second; 52 55 } 56 } 57 58 void nextUsage() { 59 ++next_usage_id; 53 60 } 54 61 … … 65 72 // ditto for assertion names, the next level in 66 73 level++; 67 // acceptAll( td->assertions, *this ); 68 } // for 69 } // if 74 } 75 } 70 76 } 71 77 … … 77 83 78 84 const ast::TypeInstType * rename( const ast::TypeInstType * type ) { 79 mapConstIterator it = nameMap.find( type->name ); 80 if ( it != nameMap.end() ) { 81 ast::TypeInstType * mutType = ast::mutate( type ); 82 mutType->name = it->second; 83 type = mutType; 84 } 85 // rename 86 auto it = idMap.find( type->name ); 87 if ( it != idMap.end() ) { 88 // unconditionally mutate because map will *always* have different name 89 ast::TypeInstType * mut = ast::shallowCopy( type ); 90 // reconcile base node since some copies might have been made 91 mut->base = it->second.base; 92 mut->formal_usage = it->second.formal_usage; 93 mut->expr_id = it->second.expr_id; 94 type = mut; 95 } 96 85 97 return type; 86 98 } 87 99 88 template<typename NodeT> 89 const NodeT * openLevel( const NodeT * type ) { 90 if ( !type->forall.empty() ) { 91 nameMap.beginScope(); 92 // Load new names from this forall clause and perform renaming. 93 NodeT * mutType = ast::mutate( type ); 94 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 95 std::ostringstream output; 96 output << "_" << resetCount << "_" << level << "_" << td->name; 97 std::string newname( output.str() ); 98 nameMap[ td->name ] = newname; 99 ++level; 100 101 ast::TypeDecl * decl = ast::mutate( td.get() ); 102 decl->name = newname; 103 td = decl; 104 } 105 } 106 return type; 107 } 108 109 template<typename NodeT> 110 const NodeT * closeLevel( const NodeT * type ) { 111 if ( !type->forall.empty() ) { 112 nameMap.endScope(); 113 } 114 return type; 100 const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) { 101 if ( type->forall.empty() ) return type; 102 idMap.beginScope(); 103 104 // Load new names from this forall clause and perform renaming. 105 auto mutType = ast::shallowCopy( type ); 106 // assert( type == mutType && "mutated type must be unique from ForallSubstitutor" ); 107 for ( auto & td : mutType->forall ) { 108 auto mut = ast::shallowCopy( td.get() ); 109 // assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" ); 110 111 if (mode == GEN_EXPR_ID) { 112 mut->expr_id = next_expr_id; 113 mut->formal_usage = -1; 114 ++next_expr_id; 115 } 116 else if (mode == GEN_USAGE) { 117 assertf(mut->expr_id, "unfilled expression id in generating candidate type"); 118 mut->formal_usage = next_usage_id; 119 } 120 else { 121 assert(false); 122 } 123 idMap[ td->name ] = ast::TypeInstType::TypeEnvKey(*mut); 124 125 td = mut; 126 } 127 128 return mutType; 129 } 130 131 void closeLevel( const ast::FunctionType * type ) { 132 if ( type->forall.empty() ) return; 133 idMap.endScope(); 115 134 } 116 135 }; … … 119 138 RenamingData renaming; 120 139 121 struct RenameVars {140 struct RenameVars_old { 122 141 void previsit( TypeInstType * instType ) { 123 142 renaming.openLevel( (Type*)instType ); … … 130 149 renaming.closeLevel( type ); 131 150 } 151 }; 152 153 struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ { 154 RenameMode mode; 132 155 133 156 const ast::FunctionType * previsit( const ast::FunctionType * type ) { 134 return renaming.openLevel( type ); 135 } 157 return renaming.openLevel( type, mode ); 158 } 159 160 /* 136 161 const ast::StructInstType * previsit( const ast::StructInstType * type ) { 137 162 return renaming.openLevel( type ); … … 143 168 return renaming.openLevel( type ); 144 169 } 170 */ 171 145 172 const ast::TypeInstType * previsit( const ast::TypeInstType * type ) { 146 return renaming.rename( renaming.openLevel( type ) ); 147 } 148 const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) { 149 return renaming.closeLevel( type ); 173 if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type 174 return renaming.rename( type ); 175 } 176 void postvisit( const ast::FunctionType * type ) { 177 renaming.closeLevel( type ); 150 178 } 151 179 }; … … 154 182 155 183 void renameTyVars( Type * t ) { 156 PassVisitor<RenameVars > renamer;184 PassVisitor<RenameVars_old> renamer; 157 185 t->accept( renamer ); 158 186 } 159 187 160 const ast::Type * renameTyVars( const ast::Type * t ) { 161 ast::Pass<RenameVars> renamer; 188 const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) { 189 // ast::Type *tc = ast::deepCopy(t); 190 ast::Pass<RenameVars_new> renamer; 191 renamer.core.mode = mode; 192 if (mode == GEN_USAGE && reset) { 193 renaming.nextUsage(); 194 } 162 195 return t->accept( renamer ); 163 196 } … … 165 198 void resetTyVarRenaming() { 166 199 renaming.reset(); 200 renaming.nextUsage(); 167 201 } 168 202 -
src/ResolvExpr/RenameVars.h
rbdfc032 reef8dfb 30 30 /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID 31 31 void renameTyVars( Type * ); 32 const ast::Type * renameTyVars( const ast::Type * ); 32 33 enum RenameMode { 34 GEN_USAGE, // for type in VariableExpr 35 GEN_EXPR_ID // for type in decl 36 }; 37 const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true ); 38 33 39 34 40 /// resets internal state of renamer to avoid overflow 35 41 void resetTyVarRenaming(); 42 43 36 44 } // namespace ResolvExpr 37 45 -
src/ResolvExpr/ResolvMode.h
rbdfc032 reef8dfb 22 22 const bool prune; ///< Prune alternatives to min-cost per return type? [true] 23 23 const bool failFast; ///< Fail on no resulting alternatives? [true] 24 const bool satisfyAssns; ///< Satisfy assertions? [false]25 24 26 private: 27 constexpr ResolvMode(bool a, bool p, bool ff, bool sa) 28 : adjust(a), prune(p), failFast(ff), satisfyAssns(sa) {} 25 constexpr ResolvMode(bool a, bool p, bool ff) 26 : adjust(a), prune(p), failFast(ff) {} 29 27 30 public:31 28 /// Default settings 32 constexpr ResolvMode() : adjust(false), prune(true), failFast(true) , satisfyAssns(false){}29 constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {} 33 30 34 31 /// With adjust flag set; turns array and function types into equivalent pointers 35 static constexpr ResolvMode withAdjustment() { return { true, true, true , false}; }32 static constexpr ResolvMode withAdjustment() { return { true, true, true }; } 36 33 37 34 /// With adjust flag set but prune unset; pruning ensures there is at least one alternative 38 35 /// per result type 39 static constexpr ResolvMode withoutPrune() { return { true, false, true , false}; }36 static constexpr ResolvMode withoutPrune() { return { true, false, true }; } 40 37 41 38 /// With adjust and prune flags set but failFast unset; failFast ensures there is at least 42 39 /// one resulting alternative 43 static constexpr ResolvMode withoutFailFast() { return { true, true, false , false}; }40 static constexpr ResolvMode withoutFailFast() { return { true, true, false }; } 44 41 45 42 /// The same mode, but with satisfyAssns turned on; for top-level calls 46 ResolvMode atTopLevel() const { return { adjust, prune, failFast, true}; }43 ResolvMode atTopLevel() const { return { adjust, true, failFast }; } 47 44 }; 48 45 } // namespace ResolvExpr -
src/ResolvExpr/ResolveAssertions.cc
rbdfc032 reef8dfb 277 277 const DeclarationWithType * candidate = cdata.id; 278 278 279 // build independent unification context for candidate 279 // ignore deleted candidates. 280 // NOTE: this behavior is different from main resolver. 281 // further investigations might be needed to determine 282 // if we should implement the same rule here 283 // (i.e. error if unique best match is deleted) 284 if (candidate->isDeleted) continue; 285 286 // build independent unification context. for candidate 280 287 AssertionSet have, newNeed; 281 288 TypeEnvironment newEnv{ resn.alt.env }; -
src/ResolvExpr/ResolveTypeof.cc
rbdfc032 reef8dfb 15 15 16 16 #include "ResolveTypeof.h" 17 #include "RenameVars.h" 17 18 18 19 #include <cassert> // for assert … … 29 30 #include "SynTree/Mutator.h" // for Mutator 30 31 #include "SynTree/Type.h" // for TypeofType, Type 32 #include "SymTab/Mangler.h" 33 #include "InitTweak/InitTweak.h" // for isConstExpr 31 34 32 35 namespace SymTab { … … 99 102 // replace basetypeof(<enum>) by int 100 103 if ( dynamic_cast<EnumInstType*>(newType) ) { 101 Type* newerType = 102 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 104 Type* newerType = 105 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 103 106 newType->attributes }; 104 107 delete newType; 105 108 newType = newerType; 106 109 } 107 newType->get_qualifiers().val 110 newType->get_qualifiers().val 108 111 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals; 109 112 } else { 110 113 newType->get_qualifiers().val |= oldQuals; 111 114 } 112 115 113 116 return newType; 114 117 } … … 120 123 ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {} 121 124 122 void pre mutate( const ast::TypeofType * ) { visit_children = false; }123 124 const ast::Type * post mutate( const ast::TypeofType * typeofType ) {125 void previsit( const ast::TypeofType * ) { visit_children = false; } 126 127 const ast::Type * postvisit( const ast::TypeofType * typeofType ) { 125 128 // pass on null expression 126 129 if ( ! typeofType->expr ) return typeofType; … … 133 136 // typeof wrapping expression 134 137 ast::TypeEnvironment dummy; 135 ast::ptr< ast::Expr > newExpr = 138 ast::ptr< ast::Expr > newExpr = 136 139 resolveInVoidContext( typeofType->expr, localSymtab, dummy ); 137 140 assert( newExpr->result && ! newExpr->result->isVoid() ); … … 143 146 // replace basetypeof(<enum>) by int 144 147 if ( newType.as< ast::EnumInstType >() ) { 145 newType = new ast::BasicType{ 148 newType = new ast::BasicType{ 146 149 ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) }; 147 150 } 148 reset_qualifiers( 149 newType, 151 reset_qualifiers( 152 newType, 150 153 ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers ); 151 154 } else { … … 153 156 } 154 157 155 return newType ;158 return newType.release(); 156 159 } 157 160 }; … … 161 164 ast::Pass< ResolveTypeof_new > mutator{ symtab }; 162 165 return type->accept( mutator ); 166 } 167 168 struct FixArrayDimension { 169 // should not require a mutable symbol table - prevent pass template instantiation 170 const ast::SymbolTable & _symtab; 171 FixArrayDimension(const ast::SymbolTable & symtab): _symtab(symtab) {} 172 173 const ast::ArrayType * previsit (const ast::ArrayType * arrayType) { 174 if (!arrayType->dimension) return arrayType; 175 auto mutType = mutate(arrayType); 176 ast::ptr<ast::Type> sizetype = ast::sizeType ? ast::sizeType : new ast::BasicType(ast::BasicType::LongUnsignedInt); 177 mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, _symtab); 178 179 if (InitTweak::isConstExpr(mutType->dimension)) { 180 mutType->isVarLen = ast::LengthFlag::FixedLen; 181 } 182 else { 183 mutType->isVarLen = ast::LengthFlag::VariableLen; 184 } 185 return mutType; 186 } 187 }; 188 189 const ast::Type * fixArrayType( const ast::Type * type, const ast::SymbolTable & symtab) { 190 ast::Pass<FixArrayDimension> visitor {symtab}; 191 return type->accept(visitor); 192 } 193 194 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab ) { 195 if (!decl->isTypeFixed) { 196 auto mutDecl = mutate(decl); 197 auto resolvedType = resolveTypeof(decl->type, symtab); 198 resolvedType = fixArrayType(resolvedType, symtab); 199 mutDecl->type = resolvedType; 200 201 // check variable length if object is an array. 202 // xxx - should this be part of fixObjectType? 203 204 /* 205 if (auto arrayType = dynamic_cast<const ast::ArrayType *>(resolvedType)) { 206 auto dimExpr = findSingleExpression(arrayType->dimension, ast::sizeType, symtab); 207 if (auto varexpr = arrayType->dimension.as<ast::VariableExpr>()) {// hoisted previously 208 if (InitTweak::isConstExpr(varexpr->var.strict_as<ast::ObjectDecl>()->init)) { 209 auto mutType = mutate(arrayType); 210 mutType->isVarLen = ast::LengthFlag::VariableLen; 211 mutDecl->type = mutType; 212 } 213 } 214 } 215 */ 216 217 218 if (!mutDecl->name.empty()) 219 mutDecl->mangleName = Mangle::mangle(mutDecl); // do not mangle unnamed variables 220 221 mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID); 222 mutDecl->isTypeFixed = true; 223 return mutDecl; 224 } 225 return decl; 163 226 } 164 227 -
src/ResolvExpr/ResolveTypeof.h
rbdfc032 reef8dfb 23 23 class Type; 24 24 class SymbolTable; 25 class ObjectDecl; 25 26 } 26 27 … … 28 29 Type *resolveTypeof( Type*, const SymTab::Indexer &indexer ); 29 30 const ast::Type * resolveTypeof( const ast::Type *, const ast::SymbolTable & ); 31 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab ); 30 32 } // namespace ResolvExpr 31 33 -
src/ResolvExpr/Resolver.cc
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Sun May 17 12:17:01 2015 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed May 29 11:00:00 201913 // Update Count : 24 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Mar 27 11:58:00 2020 13 // Update Count : 242 14 14 // 15 15 … … 26 26 #include "RenameVars.h" // for RenameVars, global_renamer 27 27 #include "Resolver.h" 28 #include "ResolveTypeof.h" 28 29 #include "ResolvMode.h" // for ResolvMode 29 30 #include "typeops.h" // for extractResultType 30 31 #include "Unify.h" // for unify 32 #include "CompilationState.h" 31 33 #include "AST/Chain.hpp" 32 34 #include "AST/Decl.hpp" … … 38 40 #include "Common/PassVisitor.h" // for PassVisitor 39 41 #include "Common/SemanticError.h" // for SemanticError 42 #include "Common/Stats/ResolveTime.h" // for ResolveTime::start(), ResolveTime::stop() 40 43 #include "Common/utility.h" // for ValueGuard, group_iterate 41 44 #include "InitTweak/GenInit.h" … … 44 47 #include "SymTab/Autogen.h" // for SizeType 45 48 #include "SymTab/Indexer.h" // for Indexer 49 #include "SymTab/Mangler.h" // for Mangler 46 50 #include "SynTree/Declaration.h" // for ObjectDecl, TypeDecl, Declar... 47 51 #include "SynTree/Expression.h" // for Expression, CastExpr, InitExpr … … 84 88 void previsit( ThrowStmt * throwStmt ); 85 89 void previsit( CatchStmt * catchStmt ); 90 void postvisit( CatchStmt * catchStmt ); 86 91 void previsit( WaitForStmt * stmt ); 87 92 … … 559 564 // TODO: Replace *exception type with &exception type. 560 565 if ( throwStmt->get_expr() ) { 561 const StructDecl * exception_decl = indexer.lookupStruct( "__cfa abi_ehm__base_exception_t" );566 const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" ); 562 567 assert( exception_decl ); 563 568 Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) ); … … 567 572 568 573 void Resolver_old::previsit( CatchStmt * catchStmt ) { 574 // Until we are very sure this invarent (ifs that move between passes have thenPart) 575 // holds, check it. This allows a check for when to decode the mangling. 576 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) { 577 assert( ifStmt->thenPart ); 578 } 579 // Encode the catchStmt so the condition can see the declaration. 569 580 if ( catchStmt->cond ) { 570 findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer ); 581 IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body ); 582 catchStmt->cond = nullptr; 583 catchStmt->body = ifStmt; 584 } 585 } 586 587 void Resolver_old::postvisit( CatchStmt * catchStmt ) { 588 // Decode the catchStmt so everything is stored properly. 589 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ); 590 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) { 591 assert( ifStmt->condition ); 592 assert( ifStmt->elsePart ); 593 catchStmt->cond = ifStmt->condition; 594 catchStmt->body = ifStmt->elsePart; 595 ifStmt->condition = nullptr; 596 ifStmt->elsePart = nullptr; 597 delete ifStmt; 571 598 } 572 599 } … … 941 968 namespace { 942 969 /// Finds deleted expressions in an expression tree 943 struct DeleteFinder_new final : public ast::WithShortCircuiting {944 const ast::DeletedExpr * delExpr= nullptr;970 struct DeleteFinder_new final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder_new> { 971 const ast::DeletedExpr * result = nullptr; 945 972 946 973 void previsit( const ast::DeletedExpr * expr ) { 947 if ( delExpr ) { visit_children = false; } 948 else { delExpr = expr; } 949 } 950 951 void previsit( const ast::Expr * ) { 952 if ( delExpr ) { visit_children = false; } 974 if ( result ) { visit_children = false; } 975 else { result = expr; } 976 } 977 978 void previsit( const ast::Expr * expr ) { 979 if ( result ) { visit_children = false; } 980 if (expr->inferred.hasParams()) { 981 for (auto & imp : expr->inferred.inferParams() ) { 982 imp.second.expr->accept(*visitor); 983 } 984 } 953 985 } 954 986 }; 955 987 } // anonymous namespace 956 957 988 /// Check if this expression is or includes a deleted expression 958 989 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) { 959 ast::Pass<DeleteFinder_new> finder; 960 expr->accept( finder ); 961 return finder.pass.delExpr; 990 return ast::Pass<DeleteFinder_new>::read( expr ); 962 991 } 963 992 … … 1049 1078 /// Strips extraneous casts out of an expression 1050 1079 struct StripCasts_new final { 1051 const ast::Expr * post mutate( const ast::CastExpr * castExpr ) {1080 const ast::Expr * postvisit( const ast::CastExpr * castExpr ) { 1052 1081 if ( 1053 castExpr->isGenerated 1082 castExpr->isGenerated == ast::GeneratedCast 1054 1083 && typesCompatible( castExpr->arg->result, castExpr->result ) 1055 1084 ) { … … 1083 1112 } 1084 1113 1085 /// Establish post-resolver invariants for expressions 1114 1115 } // anonymous namespace 1116 /// Establish post-resolver invariants for expressions 1086 1117 void finishExpr( 1087 1118 ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env, … … 1096 1127 StripCasts_new::strip( expr ); 1097 1128 } 1098 } // anonymous namespace1099 1100 1129 1101 1130 ast::ptr< ast::Expr > resolveInVoidContext( … … 1105 1134 1106 1135 // set up and resolve expression cast to void 1107 ast:: CastExpr *untyped = new ast::CastExpr{ expr };1136 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr }; 1108 1137 CandidateRef choice = findUnfinishedKindExpression( 1109 1138 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() ); … … 1117 1146 } 1118 1147 1119 namespace { 1120 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1148 /// Resolve `untyped` to the expression whose candidate is the best match for a `void` 1121 1149 /// context. 1122 1150 ast::ptr< ast::Expr > findVoidExpression( 1123 1151 const ast::Expr * untyped, const ast::SymbolTable & symtab 1124 1152 ) { 1125 resetTyVarRenaming();1126 1153 ast::TypeEnvironment env; 1127 1154 ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env ); … … 1129 1156 return newExpr; 1130 1157 } 1158 1159 namespace { 1160 1131 1161 1132 1162 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the … … 1140 1170 CandidateRef choice = 1141 1171 findUnfinishedKindExpression( untyped, symtab, kind, pred, mode ); 1142 finishExpr( choice->expr, choice->env, untyped->env );1172 ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env ); 1143 1173 return std::move( choice->expr ); 1144 1174 } … … 1148 1178 const ast::Expr * untyped, const ast::SymbolTable & symtab 1149 1179 ) { 1150 return findKindExpression( untyped, symtab ); 1180 Stats::ResolveTime::start( untyped ); 1181 auto res = findKindExpression( untyped, symtab ); 1182 Stats::ResolveTime::stop(); 1183 return res; 1151 1184 } 1152 1185 } // anonymous namespace 1153 1186 1154 1155 1156 1157 1158 1159 1160 1161 1162 1187 ast::ptr< ast::Expr > findSingleExpression( 1188 const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab 1189 ) { 1190 assert( untyped && type ); 1191 ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type }; 1192 ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab ); 1193 removeExtraneousCast( newExpr, symtab ); 1194 return newExpr; 1195 } 1163 1196 1164 1197 namespace { 1198 bool structOrUnion( const Candidate & i ) { 1199 const ast::Type * t = i.expr->result->stripReferences(); 1200 return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t ); 1201 } 1165 1202 /// Predicate for "Candidate has integral type" 1166 1203 bool hasIntegralType( const Candidate & i ) { … … 1198 1235 template<typename Iter> 1199 1236 inline bool nextMutex( Iter & it, const Iter & end ) { 1200 while ( it != end && ! (*it)-> get_type()->is_mutex() ) { ++it; }1237 while ( it != end && ! (*it)->is_mutex() ) { ++it; } 1201 1238 return it != end; 1202 1239 } … … 1210 1247 ast::ptr< ast::Type > functionReturn = nullptr; 1211 1248 ast::CurrentObject currentObject; 1249 // for work previously in GenInit 1250 static InitTweak::ManagedTypes_new managedTypes; 1251 1212 1252 bool inEnumDecl = false; 1213 1253 1214 1254 public: 1255 static size_t traceId; 1215 1256 Resolver_new() = default; 1216 1257 Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; } 1217 1258 1218 voidprevisit( const ast::FunctionDecl * );1259 const ast::FunctionDecl * previsit( const ast::FunctionDecl * ); 1219 1260 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * ); 1220 void previsit( const ast::ObjectDecl * ); 1261 const ast::ObjectDecl * previsit( const ast::ObjectDecl * ); 1262 void previsit( const ast::AggregateDecl * ); 1263 void previsit( const ast::StructDecl * ); 1221 1264 void previsit( const ast::EnumDecl * ); 1222 1265 const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * ); … … 1237 1280 const ast::ThrowStmt * previsit( const ast::ThrowStmt * ); 1238 1281 const ast::CatchStmt * previsit( const ast::CatchStmt * ); 1282 const ast::CatchStmt * postvisit( const ast::CatchStmt * ); 1239 1283 const ast::WaitForStmt * previsit( const ast::WaitForStmt * ); 1284 const ast::WithStmt * previsit( const ast::WithStmt * ); 1240 1285 1241 1286 const ast::SingleInit * previsit( const ast::SingleInit * ); 1242 1287 const ast::ListInit * previsit( const ast::ListInit * ); 1243 1288 const ast::ConstructorInit * previsit( const ast::ConstructorInit * ); 1289 1290 void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd); 1291 1292 void beginScope() { managedTypes.beginScope(); } 1293 void endScope() { managedTypes.endScope(); } 1294 bool on_error(ast::ptr<ast::Decl> & decl); 1244 1295 }; 1245 1246 void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) { 1247 ast::Pass< Resolver_new > resolver; 1248 accept_all( translationUnit, resolver ); 1296 // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver"); 1297 1298 InitTweak::ManagedTypes_new Resolver_new::managedTypes; 1299 1300 void resolve( ast::TranslationUnit& translationUnit ) { 1301 ast::Pass< Resolver_new >::run( translationUnit ); 1249 1302 } 1250 1303 … … 1257 1310 } 1258 1311 1259 ast::ptr< ast::Expr >resolveStmtExpr(1312 const ast::Expr * resolveStmtExpr( 1260 1313 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab 1261 1314 ) { 1262 1315 assert( stmtExpr ); 1263 1316 ast::Pass< Resolver_new > resolver{ symtab }; 1264 ast::ptr< ast::Expr > ret = stmtExpr; 1265 ret = ret->accept( resolver ); 1266 strict_dynamic_cast< ast::StmtExpr * >( ret.get_and_mutate() )->computeResult(); 1317 auto ret = mutate(stmtExpr->accept(resolver)); 1318 strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult(); 1267 1319 return ret; 1268 1320 } 1269 1321 1270 void Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) { 1322 namespace { 1323 const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ast::SymbolTable & symtab) { 1324 std::string name = attr->normalizedName(); 1325 if (name == "constructor" || name == "destructor") { 1326 if (attr->params.size() == 1) { 1327 auto arg = attr->params.front(); 1328 auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), symtab ); 1329 auto result = eval(arg); 1330 1331 auto mutAttr = mutate(attr); 1332 mutAttr->params.front() = resolved; 1333 if (! result.second) { 1334 SemanticWarning(loc, Warning::GccAttributes, 1335 toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) ); 1336 } 1337 else { 1338 auto priority = result.first; 1339 if (priority < 101) { 1340 SemanticWarning(loc, Warning::GccAttributes, 1341 toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) ); 1342 } else if (priority < 201 && ! buildingLibrary()) { 1343 SemanticWarning(loc, Warning::GccAttributes, 1344 toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) ); 1345 } 1346 } 1347 return mutAttr; 1348 } else if (attr->params.size() > 1) { 1349 SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) ); 1350 } else { 1351 SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) ); 1352 } 1353 } 1354 return attr; 1355 } 1356 } 1357 1358 const ast::FunctionDecl * Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) { 1271 1359 GuardValue( functionReturn ); 1360 1361 assert (functionDecl->unique()); 1362 if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) { 1363 SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations"); 1364 } 1365 1366 if (!functionDecl->isTypeFixed) { 1367 auto mutDecl = mutate(functionDecl); 1368 auto mutType = mutDecl->type.get_and_mutate(); 1369 1370 for (auto & attr: mutDecl->attributes) { 1371 attr = handleAttribute(mutDecl->location, attr, symtab); 1372 } 1373 1374 // handle assertions 1375 1376 symtab.enterScope(); 1377 mutType->forall.clear(); 1378 mutType->assertions.clear(); 1379 for (auto & typeParam : mutDecl->type_params) { 1380 symtab.addType(typeParam); 1381 mutType->forall.emplace_back(new ast::TypeInstType(typeParam->name, typeParam)); 1382 } 1383 for (auto & asst : mutDecl->assertions) { 1384 asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab); 1385 symtab.addId(asst); 1386 mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst)); 1387 } 1388 1389 // temporarily adds params to symbol table. 1390 // actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl) 1391 1392 std::vector<ast::ptr<ast::Type>> paramTypes; 1393 std::vector<ast::ptr<ast::Type>> returnTypes; 1394 1395 for (auto & param : mutDecl->params) { 1396 param = fixObjectType(param.strict_as<ast::ObjectDecl>(), symtab); 1397 symtab.addId(param); 1398 paramTypes.emplace_back(param->get_type()); 1399 } 1400 for (auto & ret : mutDecl->returns) { 1401 ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), symtab); 1402 returnTypes.emplace_back(ret->get_type()); 1403 } 1404 // since function type in decl is just a view of param types, need to update that as well 1405 mutType->params = std::move(paramTypes); 1406 mutType->returns = std::move(returnTypes); 1407 1408 auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID)); 1409 1410 std::list<ast::ptr<ast::Stmt>> newStmts; 1411 resolveWithExprs (mutDecl->withExprs, newStmts); 1412 1413 if (mutDecl->stmts) { 1414 auto mutStmt = mutDecl->stmts.get_and_mutate(); 1415 mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts)); 1416 mutDecl->stmts = mutStmt; 1417 } 1418 1419 symtab.leaveScope(); 1420 1421 mutDecl->type = renamedType; 1422 mutDecl->mangleName = Mangle::mangle(mutDecl); 1423 mutDecl->isTypeFixed = true; 1424 functionDecl = mutDecl; 1425 } 1426 managedTypes.handleDWT(functionDecl); 1427 1272 1428 functionReturn = extractResultType( functionDecl->type ); 1429 return functionDecl; 1273 1430 } 1274 1431 … … 1276 1433 // default value expressions have an environment which shouldn't be there and trips up 1277 1434 // later passes. 1278 as t::ptr< ast::FunctionDecl > ret = functionDecl;1279 for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {1280 const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i]; 1281 1282 if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {1435 assert( functionDecl->unique() ); 1436 ast::FunctionType * mutType = mutate( functionDecl->type.get() ); 1437 1438 for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) { 1439 if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) { 1283 1440 if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) { 1284 1441 if ( init->value->env == nullptr ) continue; 1285 1442 // clone initializer minus the initializer environment 1286 ast::chain_mutate( ret ) 1287 ( &ast::FunctionDecl::type ) 1288 ( &ast::FunctionType::params )[i] 1289 ( &ast::ObjectDecl::init ) 1290 ( &ast::SingleInit::value )->env = nullptr; 1291 1292 assert( functionDecl != ret.get() || functionDecl->unique() ); 1293 assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env ); 1443 auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() ); 1444 auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() ); 1445 auto mutValue = mutate( mutInit->value.get() ); 1446 1447 mutValue->env = nullptr; 1448 mutInit->value = mutValue; 1449 mutParam->init = mutInit; 1450 mutType->params[i] = mutParam; 1451 1452 assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env); 1294 1453 } 1295 1454 } 1296 1455 } 1297 return ret.get(); 1298 } 1299 1300 void Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) { 1456 mutate_field(functionDecl, &ast::FunctionDecl::type, mutType); 1457 return functionDecl; 1458 } 1459 1460 const ast::ObjectDecl * Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) { 1301 1461 // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()], 1302 1462 // class-variable `initContext` is changed multiple times because the LHS is analyzed … … 1306 1466 // selecting the RHS. 1307 1467 GuardValue( currentObject ); 1308 currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() }; 1468 1309 1469 if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) { 1310 1470 // enumerator initializers should not use the enum type to initialize, since the 1311 1471 // enum type is still incomplete at this point. Use `int` instead. 1472 objectDecl = fixObjectType(objectDecl, symtab); 1312 1473 currentObject = ast::CurrentObject{ 1313 1474 objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } }; 1314 1475 } 1476 else { 1477 if (!objectDecl->isTypeFixed) { 1478 auto newDecl = fixObjectType(objectDecl, symtab); 1479 auto mutDecl = mutate(newDecl); 1480 1481 // generate CtorInit wrapper when necessary. 1482 // in certain cases, fixObjectType is called before reaching 1483 // this object in visitor pass, thus disabling CtorInit codegen. 1484 // this happens on aggregate members and function parameters. 1485 if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) { 1486 // constructed objects cannot be designated 1487 if ( InitTweak::isDesignated( mutDecl->init ) ) SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" ); 1488 // constructed objects should not have initializers nested too deeply 1489 if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " ); 1490 1491 mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl ); 1492 } 1493 1494 objectDecl = mutDecl; 1495 } 1496 currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() }; 1497 } 1498 1499 return objectDecl; 1500 } 1501 1502 void Resolver_new::previsit( const ast::AggregateDecl * _aggDecl ) { 1503 auto aggDecl = mutate(_aggDecl); 1504 assertf(aggDecl == _aggDecl, "type declarations must be unique"); 1505 1506 for (auto & member: aggDecl->members) { 1507 // nested type decls are hoisted already. no need to do anything 1508 if (auto obj = member.as<ast::ObjectDecl>()) { 1509 member = fixObjectType(obj, symtab); 1510 } 1511 } 1512 } 1513 1514 void Resolver_new::previsit( const ast::StructDecl * structDecl ) { 1515 previsit(static_cast<const ast::AggregateDecl *>(structDecl)); 1516 managedTypes.handleStruct(structDecl); 1315 1517 } 1316 1518 … … 1318 1520 // in case we decide to allow nested enums 1319 1521 GuardValue( inEnumDecl ); 1320 inEnumDecl = false; 1321 } 1522 inEnumDecl = true; 1523 // don't need to fix types for enum fields 1524 } 1525 1322 1526 1323 1527 const ast::StaticAssertDecl * Resolver_new::previsit( … … 1332 1536 const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) { 1333 1537 if ( type->dimension ) { 1334 #warning should use new equivalent to Validate::SizeType rather than sizeType here 1335 ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt }; 1538 ast::ptr< ast::Type > sizeType = ast::sizeType; 1336 1539 ast::mutate_field( 1337 1540 type, &PtrType::dimension, … … 1454 1657 if ( throwStmt->expr ) { 1455 1658 const ast::StructDecl * exceptionDecl = 1456 symtab.lookupStruct( "__cfa abi_ehm__base_exception_t" );1659 symtab.lookupStruct( "__cfaehm_base_exception_t" ); 1457 1660 assert( exceptionDecl ); 1458 1661 ast::ptr< ast::Type > exceptType = … … 1466 1669 1467 1670 const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) { 1671 // Until we are very sure this invarent (ifs that move between passes have thenPart) 1672 // holds, check it. This allows a check for when to decode the mangling. 1673 if ( auto ifStmt = catchStmt->body.as<ast::IfStmt>() ) { 1674 assert( ifStmt->thenPart ); 1675 } 1676 // Encode the catchStmt so the condition can see the declaration. 1468 1677 if ( catchStmt->cond ) { 1469 ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool }; 1470 catchStmt = ast::mutate_field( 1471 catchStmt, &ast::CatchStmt::cond, 1472 findSingleExpression( catchStmt->cond, boolType, symtab ) ); 1678 ast::CatchStmt * stmt = mutate( catchStmt ); 1679 stmt->body = new ast::IfStmt( stmt->location, stmt->cond, nullptr, stmt->body ); 1680 stmt->cond = nullptr; 1681 return stmt; 1682 } 1683 return catchStmt; 1684 } 1685 1686 const ast::CatchStmt * Resolver_new::postvisit( const ast::CatchStmt * catchStmt ) { 1687 // Decode the catchStmt so everything is stored properly. 1688 const ast::IfStmt * ifStmt = catchStmt->body.as<ast::IfStmt>(); 1689 if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) { 1690 assert( ifStmt->cond ); 1691 assert( ifStmt->elsePart ); 1692 ast::CatchStmt * stmt = ast::mutate( catchStmt ); 1693 stmt->cond = ifStmt->cond; 1694 stmt->body = ifStmt->elsePart; 1695 // ifStmt should be implicately deleted here. 1696 return stmt; 1473 1697 } 1474 1698 return catchStmt; … … 1587 1811 // Check if the argument matches the parameter type in the current 1588 1812 // scope 1589 ast::ptr< ast::Type > paramType = (*param)->get_type();1813 // ast::ptr< ast::Type > paramType = (*param)->get_type(); 1590 1814 if ( 1591 1815 ! unify( 1592 arg->expr->result, paramType, resultEnv, need, have, open,1816 arg->expr->result, *param, resultEnv, need, have, open, 1593 1817 symtab ) 1594 1818 ) { … … 1597 1821 ss << "candidate function not viable: no known conversion " 1598 1822 "from '"; 1599 ast::print( ss, (*param)->get_type());1823 ast::print( ss, *param ); 1600 1824 ss << "' to '"; 1601 1825 ast::print( ss, arg->expr->result ); … … 1727 1951 } 1728 1952 1953 const ast::WithStmt * Resolver_new::previsit( const ast::WithStmt * withStmt ) { 1954 auto mutStmt = mutate(withStmt); 1955 resolveWithExprs(mutStmt->exprs, stmtsToAddBefore); 1956 return mutStmt; 1957 } 1958 1959 void Resolver_new::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) { 1960 for (auto & expr : exprs) { 1961 // only struct- and union-typed expressions are viable candidates 1962 expr = findKindExpression( expr, symtab, structOrUnion, "with expression" ); 1963 1964 // if with expression might be impure, create a temporary so that it is evaluated once 1965 if ( Tuples::maybeImpure( expr ) ) { 1966 static UniqueName tmpNamer( "_with_tmp_" ); 1967 const CodeLocation loc = expr->location; 1968 auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) ); 1969 expr = new ast::VariableExpr( loc, tmp ); 1970 stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) ); 1971 if ( InitTweak::isConstructable( tmp->type ) ) { 1972 // generate ctor/dtor and resolve them 1973 tmp->init = InitTweak::genCtorInit( loc, tmp ); 1974 } 1975 // since tmp is freshly created, this should modify tmp in-place 1976 tmp->accept( *visitor ); 1977 } 1978 } 1979 } 1729 1980 1730 1981 … … 1822 2073 } 1823 2074 2075 // suppress error on autogen functions and mark invalid autogen as deleted. 2076 bool Resolver_new::on_error(ast::ptr<ast::Decl> & decl) { 2077 if (auto functionDecl = decl.as<ast::FunctionDecl>()) { 2078 // xxx - can intrinsic gen ever fail? 2079 if (functionDecl->linkage == ast::Linkage::AutoGen) { 2080 auto mutDecl = mutate(functionDecl); 2081 mutDecl->isDeleted = true; 2082 mutDecl->stmts = nullptr; 2083 decl = mutDecl; 2084 return false; 2085 } 2086 } 2087 return true; 2088 } 2089 1824 2090 } // namespace ResolvExpr 1825 2091 -
src/ResolvExpr/Resolver.h
rbdfc032 reef8dfb 35 35 class StmtExpr; 36 36 class SymbolTable; 37 struct TranslationUnit; 37 38 class Type; 38 39 class TypeEnvironment; … … 55 56 56 57 /// Checks types and binds syntactic constructs to typed representations 57 void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );58 void resolve( ast::TranslationUnit& translationUnit ); 58 59 /// Searches expr and returns the first DeletedExpr found, otherwise nullptr 59 60 const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ); … … 62 63 ast::ptr< ast::Expr > resolveInVoidContext( 63 64 const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env ); 64 /// Resolve `untyped` to the single expression whose candidate is the best match for the 65 /// Resolve `untyped` to the single expression whose candidate is the best match for the 65 66 /// given type. 66 67 ast::ptr< ast::Expr > findSingleExpression( 67 68 const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab ); 69 ast::ptr< ast::Expr > findVoidExpression( 70 const ast::Expr * untyped, const ast::SymbolTable & symtab); 68 71 /// Resolves a constructor init expression 69 ast::ptr< ast::Init > resolveCtorInit( 72 ast::ptr< ast::Init > resolveCtorInit( 70 73 const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab ); 71 /// Resolves a statement expression 72 ast::ptr< ast::Expr > resolveStmtExpr(74 /// Resolves a statement expression 75 const ast::Expr * resolveStmtExpr( 73 76 const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab ); 74 77 } // namespace ResolvExpr -
src/ResolvExpr/SatisfyAssertions.cpp
rbdfc032 reef8dfb 9 9 // Author : Aaron B. Moss 10 10 // Created On : Mon Jun 10 17:45:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Mon Jun 10 17:45:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 13:56:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 69 69 /// Reference to a single deferred item 70 70 struct DeferRef { 71 const ast:: DeclWithType * decl;71 const ast::VariableExpr * expr; 72 72 const ast::AssertionSetValue & info; 73 73 const AssnCandidate & match; … … 77 77 /// Acts like an indexed list of DeferRef 78 78 struct DeferItem { 79 const ast:: DeclWithType * decl;79 const ast::VariableExpr * expr; 80 80 const ast::AssertionSetValue & info; 81 81 AssnCandidateList matches; 82 82 83 83 DeferItem( 84 const ast:: DeclWithType* d, const ast::AssertionSetValue & i, AssnCandidateList && ms )85 : decl( d ), info( i ), matches( std::move( ms ) ) {}84 const ast::VariableExpr * d, const ast::AssertionSetValue & i, AssnCandidateList && ms ) 85 : expr( d ), info( i ), matches( std::move( ms ) ) {} 86 86 87 87 bool empty() const { return matches.empty(); } … … 89 89 AssnCandidateList::size_type size() const { return matches.size(); } 90 90 91 DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; }91 DeferRef operator[] ( unsigned i ) const { return { expr, info, matches[i] }; } 92 92 }; 93 93 … … 138 138 void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) { 139 139 for ( auto & i : have ) { 140 if ( i.second.isUsed ) { symtab.addId( i.first ); }140 if ( i.second.isUsed ) { symtab.addId( i.first->var ); } 141 141 } 142 142 } … … 144 144 /// Binds a single assertion, updating satisfaction state 145 145 void bindAssertion( 146 const ast:: DeclWithType * decl, const ast::AssertionSetValue & info, CandidateRef & cand,146 const ast::VariableExpr * expr, const ast::AssertionSetValue & info, CandidateRef & cand, 147 147 AssnCandidate & match, InferCache & inferred 148 148 ) { … … 156 156 157 157 // place newly-inferred assertion in proper location in cache 158 inferred[ info.resnSlot ][ decl->uniqueId ] = ast::ParamEntry{159 candidate->uniqueId, candidate, match.adjType, decl->get_type(), varExpr };158 inferred[ info.resnSlot ][ expr->var->uniqueId ] = ast::ParamEntry{ 159 candidate->uniqueId, candidate, match.adjType, expr->result, varExpr }; 160 160 } 161 161 … … 167 167 // find candidates that unify with the desired type 168 168 AssnCandidateList matches; 169 for ( const ast::SymbolTable::IdData & cdata : sat.symtab.lookupId( assn.first->name ) ) { 169 170 std::vector<ast::SymbolTable::IdData> candidates; 171 auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->var->name); 172 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) { 173 // prefilter special decls by argument type, if already known 174 ast::ptr<ast::Type> thisArgType = assn.first->result.strict_as<ast::PointerType>()->base 175 .strict_as<ast::FunctionType>()->params[0] 176 .strict_as<ast::ReferenceType>()->base; 177 sat.cand->env.apply(thisArgType); 178 179 std::string otypeKey = ""; 180 if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer; 181 else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams); 182 183 candidates = sat.symtab.specialLookupId(kind, otypeKey); 184 } 185 else { 186 candidates = sat.symtab.lookupId(assn.first->var->name); 187 } 188 for ( const ast::SymbolTable::IdData & cdata : candidates ) { 170 189 const ast::DeclWithType * candidate = cdata.id; 190 191 // ignore deleted candidates. 192 // NOTE: this behavior is different from main resolver. 193 // further investigations might be needed to determine 194 // if we should implement the same rule here 195 // (i.e. error if unique best match is deleted) 196 if (candidate->isDeleted && candidate->linkage == ast::Linkage::AutoGen) continue; 171 197 172 198 // build independent unification context for candidate … … 174 200 ast::TypeEnvironment newEnv{ sat.cand->env }; 175 201 ast::OpenVarSet newOpen{ sat.cand->open }; 176 ast::ptr< ast::Type > toType = assn.first-> get_type();202 ast::ptr< ast::Type > toType = assn.first->result; 177 203 ast::ptr< ast::Type > adjType = 178 renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ) );204 renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ), GEN_USAGE, false ); 179 205 180 206 // only keep candidates which unify … … 188 214 189 215 matches.emplace_back( 190 cdata, adjType, std::move( newEnv ), std::move( newNeed ), std::move( have),216 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 191 217 std::move( newOpen ), crntResnSlot ); 192 218 } … … 229 255 InferMatcher( InferCache & inferred ) : inferred( inferred ) {} 230 256 231 const ast::Expr * post mutate( const ast::Expr * expr ) {257 const ast::Expr * postvisit( const ast::Expr * expr ) { 232 258 // Skip if no slots to find 233 if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr; 234 259 if ( !expr->inferred.hasSlots() ) return expr; 260 // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr; 261 std::vector<UniqueId> missingSlots; 235 262 // find inferred parameters for resolution slots 236 ast::InferredParams newInferred;263 ast::InferredParams * newInferred = new ast::InferredParams(); 237 264 for ( UniqueId slot : expr->inferred.resnSlots() ) { 238 265 // fail if no matching assertions found 239 266 auto it = inferred.find( slot ); 240 267 if ( it == inferred.end() ) { 241 assert(!"missing assertion"); 268 // std::cerr << "missing assertion " << slot << std::endl; 269 missingSlots.push_back(slot); 270 continue; 242 271 } 243 272 … … 245 274 for ( auto & entry : it->second ) { 246 275 // recurse on inferParams of resolved expressions 247 entry.second.expr = post mutate( entry.second.expr );248 auto res = newInferred .emplace( entry );276 entry.second.expr = postvisit( entry.second.expr ); 277 auto res = newInferred->emplace( entry ); 249 278 assert( res.second && "all assertions newly placed" ); 250 279 } … … 252 281 253 282 ast::Expr * ret = mutate( expr ); 254 ret->inferred.set_inferParams( std::move( newInferred ) ); 283 ret->inferred.set_inferParams( newInferred ); 284 if (!missingSlots.empty()) ret->inferred.resnSlots() = missingSlots; 255 285 return ret; 256 286 } … … 307 337 // compute conversion cost from satisfying decl to assertion 308 338 cost += computeConversionCost( 309 assn.match.adjType, assn. decl->get_type(), symtab, env );339 assn.match.adjType, assn.expr->result, false, symtab, env ); 310 340 311 341 // mark vars+specialization on function-type assertions … … 314 344 if ( ! func ) continue; 315 345 316 for ( const a st::DeclWithType *param : func->params ) {317 cost.decSpec( specCost( param ->get_type()) );346 for ( const auto & param : func->params ) { 347 cost.decSpec( specCost( param ) ); 318 348 } 319 349 320 350 cost.incVar( func->forall.size() ); 321 351 322 for ( const ast::TypeDecl * td : func->forall ) { 323 cost.decSpec( td->assertions.size() ); 324 } 352 cost.decSpec( func->assertions.size() ); 325 353 } 326 354 } … … 357 385 358 386 /// Limit to depth of recursion of assertion satisfaction 359 static const int recursionLimit = 7;387 static const int recursionLimit = 8; 360 388 /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of 361 389 static const int deferLimit = 10; … … 389 417 if ( it != thresholds.end() && it->second < sat.costs ) goto nextSat; 390 418 391 // make initial pass at matching assertions 392 for ( auto & assn : sat.need ) { 393 // fail early if any assertion is not satisfiable 394 if ( ! satisfyAssertion( assn, sat ) ) { 419 // should a limit be imposed? worst case here is O(n^2) but very unlikely to happen. 420 for (unsigned resetCount = 0; ; ++resetCount) { 421 ast::AssertionList next; 422 resetTyVarRenaming(); 423 // make initial pass at matching assertions 424 for ( auto & assn : sat.need ) { 425 // fail early if any assertion is not satisfiable 426 if ( ! satisfyAssertion( assn, sat ) ) { 427 next.emplace_back(assn); 428 // goto nextSat; 429 } 430 } 431 // success 432 if (next.empty()) break; 433 // fail if nothing resolves 434 else if (next.size() == sat.need.size()) { 395 435 Indenter tabs{ 3 }; 396 436 std::ostringstream ss; … … 398 438 print( ss, *sat.cand, ++tabs ); 399 439 ss << (tabs-1) << "Could not satisfy assertion:\n"; 400 ast::print( ss, assn.first, tabs );440 ast::print( ss, next[0].first, tabs ); 401 441 402 442 errors.emplace_back( ss.str() ); 403 443 goto nextSat; 404 444 } 445 sat.need = std::move(next); 405 446 } 406 447 … … 421 462 ss << (tabs-1) << "Too many non-unique satisfying assignments for assertions:\n"; 422 463 for ( const auto & d : sat.deferred ) { 423 ast::print( ss, d. decl, tabs );464 ast::print( ss, d.expr, tabs ); 424 465 } 425 466 … … 439 480 ss << (tabs-1) << "No mutually-compatible satisfaction for assertions:\n"; 440 481 for ( const auto& d : sat.deferred ) { 441 ast::print( ss, d. decl, tabs );482 ast::print( ss, d.expr, tabs ); 442 483 } 443 484 … … 471 512 nextNewNeed.insert( match.need.begin(), match.need.end() ); 472 513 473 bindAssertion( r. decl, r.info, nextCand, match, nextInferred );514 bindAssertion( r.expr, r.info, nextCand, match, nextInferred ); 474 515 } 475 516 -
src/ResolvExpr/SatisfyAssertions.hpp
rbdfc032 reef8dfb 27 27 namespace ResolvExpr { 28 28 29 /// Recursively satisfies all assertions provided in a candidate; returns true if succeeds 30 void satisfyAssertions( 31 CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 29 /// Recursively satisfies all assertions provided in a candidate 30 /// returns true if it has been run (candidate has any assertions) 31 void satisfyAssertions( 32 CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 32 33 std::vector<std::string> & errors ); 33 34 -
src/ResolvExpr/SpecCost.cc
rbdfc032 reef8dfb 10 10 // Created On : Tue Oct 02 15:50:00 2018 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Jun 19 10:43:00 2019 13 // Update Count : 2 14 // 15 12 // Last Modified On : Wed Jul 3 11:07:00 2019 13 // Update Count : 3 14 // 15 16 #include <cassert> 16 17 #include <limits> 17 18 #include <list> … … 129 130 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 130 131 132 #warning Should use a standard maybe_accept 133 void maybe_accept( ast::Type const * type ) { 134 if ( type ) { 135 auto node = type->accept( *visitor ); 136 assert( node == nullptr || node == type ); 137 } 138 } 139 131 140 // Update the minimum to the new lowest non-none value. 132 141 template<typename T> … … 134 143 for ( const auto & node : list ) { 135 144 count = -1; 136 ma pper( node )->accept( *visitor);145 maybe_accept( mapper( node ) ); 137 146 if ( count != -1 && count < minimum ) minimum = count; 138 147 } … … 169 178 void previsit( const ast::FunctionType * fty ) { 170 179 int minCount = std::numeric_limits<int>::max(); 171 updateMinimumPresent( minCount, fty->params, decl_type);172 updateMinimumPresent( minCount, fty->returns, decl_type);180 updateMinimumPresent( minCount, fty->params, type_deref ); 181 updateMinimumPresent( minCount, fty->returns, type_deref ); 173 182 // Add another level to minCount if set. 174 183 count = toNoneOrInc( minCount ); … … 208 217 } 209 218 ast::Pass<SpecCounter> counter; 210 type->accept( *counter.pass.visitor );211 return counter. pass.get_count();219 type->accept( counter ); 220 return counter.core.get_count(); 212 221 } 213 222 -
src/ResolvExpr/TypeEnvironment.cc
rbdfc032 reef8dfb 20 20 #include <utility> // for pair, move 21 21 22 #include "CompilationState.h" // for deterministic_output 22 23 #include "Common/utility.h" // for maybeClone 23 24 #include "SynTree/Type.h" // for Type, FunctionType, Type::Fora... … … 106 107 107 108 void EqvClass::print( std::ostream &os, Indenter indent ) const { 108 os << "( "; 109 std::copy( vars.begin(), vars.end(), std::ostream_iterator< std::string >( os, " " ) ); 109 os << "("; 110 bool first = true; 111 for(const auto & var : vars) { 112 if(first) first = false; 113 else os << " "; 114 if( deterministic_output && isUnboundType(var) ) os << "[unbound]"; 115 else os << var; 116 } 110 117 os << ")"; 111 118 if ( type ) { … … 235 242 // check safely bindable 236 243 if ( r.type && occursIn( r.type, s.vars.begin(), s.vars.end(), *this ) ) return false; 237 244 238 245 // merge classes in 239 246 r.vars.insert( s.vars.begin(), s.vars.end() ); -
src/ResolvExpr/TypeEnvironment.h
rbdfc032 reef8dfb 149 149 iterator end() const { return env.end(); } 150 150 151 auto size() const { return env.size(); } 152 151 153 private: 152 154 ClassList env; -
src/ResolvExpr/Unify.cc
rbdfc032 reef8dfb 25 25 #include <vector> 26 26 27 #include "AST/Copy.hpp" 27 28 #include "AST/Decl.hpp" 28 29 #include "AST/Node.hpp" 29 30 #include "AST/Pass.hpp" 31 #include "AST/Print.hpp" 30 32 #include "AST/Type.hpp" 31 33 #include "AST/TypeEnvironment.hpp" … … 135 137 findOpenVars( newSecond, open, closed, need, have, FirstOpen ); 136 138 137 return unifyExact( 138 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 140 } 140 141 … … 148 149 newFirst->get_qualifiers() = Type::Qualifiers(); 149 150 newSecond->get_qualifiers() = Type::Qualifiers(); 150 /// std::cerr << "first is "; 151 /// first->print( std::cerr ); 152 /// std::cerr << std::endl << "second is "; 153 /// second->print( std::cerr ); 154 /// std::cerr << std::endl << "newFirst is "; 155 /// newFirst->print( std::cerr ); 156 /// std::cerr << std::endl << "newSecond is "; 157 /// newSecond->print( std::cerr ); 158 /// std::cerr << std::endl; 151 159 152 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 160 153 delete newFirst; … … 170 163 ast::AssertionSet need, have; 171 164 172 ast::ptr<ast::Type> newFirst{ first }, newSecond{ second }; 173 env.apply( newFirst ); 174 env.apply( newSecond ); 175 reset_qualifiers( newFirst ); 176 reset_qualifiers( newSecond ); 165 ast::Type * newFirst = shallowCopy( first ); 166 ast::Type * newSecond = shallowCopy( second ); 167 newFirst ->qualifiers = {}; 168 newSecond->qualifiers = {}; 169 ast::ptr< ast::Type > t1_(newFirst ); 170 ast::ptr< ast::Type > t2_(newSecond); 171 172 ast::ptr< ast::Type > subFirst = env.apply(newFirst).node; 173 ast::ptr< ast::Type > subSecond = env.apply(newSecond).node; 177 174 178 175 return unifyExact( 179 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 176 subFirst, 177 subSecond, 178 newEnv, need, have, open, noWiden(), symtab ); 180 179 } 181 180 … … 326 325 327 326 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) { 328 /// std::cerr << "assertion set is" << std::endl;329 /// printAssertionSet( assertions, std::cerr, 8 );330 /// std::cerr << "looking for ";331 /// assert->print( std::cerr );332 /// std::cerr << std::endl;333 327 AssertionSet::iterator i = assertions.find( assert ); 334 328 if ( i != assertions.end() ) { 335 /// std::cerr << "found it!" << std::endl;336 329 i->second.isUsed = true; 337 330 } // if … … 402 395 403 396 template< typename Iterator1, typename Iterator2 > 404 bool unify DeclList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {397 bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) { 405 398 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); }; 406 399 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) { … … 496 489 || flatOther->isTtype() 497 490 ) { 498 if ( unify DeclList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {499 if ( unify DeclList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {491 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 492 if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) { 500 493 501 494 // the original types must be used in mark assertions, since pointer comparisons are used … … 709 702 const ast::SymbolTable & symtab; 710 703 public: 704 static size_t traceId; 711 705 bool result; 712 706 … … 773 767 /// If this isn't done when satifying ttype assertions, then argument lists can have 774 768 /// different size and structure when they should be compatible. 775 struct TtypeExpander_new : public ast::WithShortCircuiting {769 struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor { 776 770 ast::TypeEnvironment & tenv; 777 771 … … 779 773 780 774 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) { 781 if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name) ) {775 if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) { 782 776 // expand ttype parameter into its actual type 783 777 if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) { … … 790 784 791 785 /// returns flattened version of `src` 792 static std::vector< ast::ptr< ast:: DeclWithType > > flattenList(793 const std::vector< ast::ptr< ast:: DeclWithType > > & src, ast::TypeEnvironment & env786 static std::vector< ast::ptr< ast::Type > > flattenList( 787 const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env 794 788 ) { 795 std::vector< ast::ptr< ast:: DeclWithType > > dst;789 std::vector< ast::ptr< ast::Type > > dst; 796 790 dst.reserve( src.size() ); 797 for ( const a st::DeclWithType *d : src ) {791 for ( const auto & d : src ) { 798 792 ast::Pass<TtypeExpander_new> expander{ env }; 799 d = d->accept( expander ); 800 auto types = flatten( d->get_type() ); 793 // TtypeExpander pass is impure (may mutate nodes in place) 794 // need to make nodes shared to prevent accidental mutation 795 ast::ptr<ast::Type> dc = d->accept(expander); 796 auto types = flatten( dc ); 801 797 for ( ast::ptr< ast::Type > & t : types ) { 802 798 // outermost const, volatile, _Atomic qualifiers in parameters should not play … … 807 803 // requirements than a non-mutex function 808 804 remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic ); 809 dst.emplace_back( new ast::ObjectDecl{ d->location, "", t });805 dst.emplace_back( t ); 810 806 } 811 807 } … … 815 811 /// Creates a tuple type based on a list of DeclWithType 816 812 template< typename Iter > 817 static ast::ptr< ast::Type > tupleFromDecls( Iter crnt, Iter end ) {813 static const ast::Type * tupleFromTypes( Iter crnt, Iter end ) { 818 814 std::vector< ast::ptr< ast::Type > > types; 819 815 while ( crnt != end ) { 820 816 // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure 821 817 // that this results in a flat tuple 822 flatten( (*crnt)->get_type(), types );818 flatten( *crnt, types ); 823 819 824 820 ++crnt; 825 821 } 826 822 827 return { new ast::TupleType{ std::move(types) }};823 return new ast::TupleType{ std::move(types) }; 828 824 } 829 825 830 826 template< typename Iter > 831 static bool unify DeclList(827 static bool unifyTypeList( 832 828 Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env, 833 829 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open, … … 835 831 ) { 836 832 while ( crnt1 != end1 && crnt2 != end2 ) { 837 const ast::Type * t1 = (*crnt1)->get_type();838 const ast::Type * t2 = (*crnt2)->get_type();833 const ast::Type * t1 = *crnt1; 834 const ast::Type * t2 = *crnt2; 839 835 bool isTuple1 = Tuples::isTtype( t1 ); 840 836 bool isTuple2 = Tuples::isTtype( t2 ); … … 844 840 // combine remainder of list2, then unify 845 841 return unifyExact( 846 t1, tupleFrom Decls( crnt2, end2 ), env, need, have, open,842 t1, tupleFromTypes( crnt2, end2 ), env, need, have, open, 847 843 noWiden(), symtab ); 848 844 } else if ( ! isTuple1 && isTuple2 ) { 849 845 // combine remainder of list1, then unify 850 846 return unifyExact( 851 tupleFrom Decls( crnt1, end1 ), t2, env, need, have, open,847 tupleFromTypes( crnt1, end1 ), t2, env, need, have, open, 852 848 noWiden(), symtab ); 853 849 } … … 864 860 if ( crnt1 != end1 ) { 865 861 // try unifying empty tuple with ttype 866 const ast::Type * t1 = (*crnt1)->get_type();862 const ast::Type * t1 = *crnt1; 867 863 if ( ! Tuples::isTtype( t1 ) ) return false; 868 864 return unifyExact( 869 t1, tupleFrom Decls( crnt2, end2 ), env, need, have, open,865 t1, tupleFromTypes( crnt2, end2 ), env, need, have, open, 870 866 noWiden(), symtab ); 871 867 } else if ( crnt2 != end2 ) { 872 868 // try unifying empty tuple with ttype 873 const ast::Type * t2 = (*crnt2)->get_type();869 const ast::Type * t2 = *crnt2; 874 870 if ( ! Tuples::isTtype( t2 ) ) return false; 875 871 return unifyExact( 876 tupleFrom Decls( crnt1, end1 ), t2, env, need, have, open,872 tupleFromTypes( crnt1, end1 ), t2, env, need, have, open, 877 873 noWiden(), symtab ); 878 874 } … … 881 877 } 882 878 883 static bool unify DeclList(884 const std::vector< ast::ptr< ast:: DeclWithType > > & list1,885 const std::vector< ast::ptr< ast:: DeclWithType > > & list2,879 static bool unifyTypeList( 880 const std::vector< ast::ptr< ast::Type > > & list1, 881 const std::vector< ast::ptr< ast::Type > > & list2, 886 882 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have, 887 883 const ast::OpenVarSet & open, const ast::SymbolTable & symtab 888 884 ) { 889 return unify DeclList(885 return unifyTypeList( 890 886 list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open, 891 887 symtab ); 892 888 } 893 889 894 static void markAssertionSet( ast::AssertionSet & assns, const ast:: DeclWithType* assn ) {890 static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) { 895 891 auto i = assns.find( assn ); 896 892 if ( i != assns.end() ) { … … 902 898 static void markAssertions( 903 899 ast::AssertionSet & assn1, ast::AssertionSet & assn2, 904 const ast:: ParameterizedType * type900 const ast::FunctionType * type 905 901 ) { 906 for ( const auto & tyvar : type->forall ) { 907 for ( const ast::DeclWithType * assert : tyvar->assertions ) { 908 markAssertionSet( assn1, assert ); 909 markAssertionSet( assn2, assert ); 910 } 902 for ( auto & assert : type->assertions ) { 903 markAssertionSet( assn1, assert ); 904 markAssertionSet( assn2, assert ); 911 905 } 912 906 } … … 932 926 ) return; 933 927 934 if ( ! unify DeclList( params, params2, tenv, need, have, open, symtab ) ) return;935 if ( ! unify DeclList(928 if ( ! unifyTypeList( params, params2, tenv, need, have, open, symtab ) ) return; 929 if ( ! unifyTypeList( 936 930 func->returns, func2->returns, tenv, need, have, open, symtab ) ) return; 937 931 … … 943 937 944 938 private: 945 template< typename RefType > 946 const RefType * handleRefType( const RefType * inst, const ast::Type * other ) { 939 // Returns: other, cast as XInstType 940 // Assigns this->result: whether types are compatible (up to generic parameters) 941 template< typename XInstType > 942 const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) { 947 943 // check that the other type is compatible and named the same 948 auto otherInst = dynamic_cast< const RefType * >( other );949 result = otherInst && inst->name == otherInst->name;944 auto otherInst = dynamic_cast< const XInstType * >( other ); 945 this->result = otherInst && inst->name == otherInst->name; 950 946 return otherInst; 951 947 } … … 968 964 } 969 965 970 template< typename RefType >971 void handleGenericRefType( const RefType * inst, const ast::Type * other ) {966 template< typename XInstType > 967 void handleGenericRefType( const XInstType * inst, const ast::Type * other ) { 972 968 // check that other type is compatible and named the same 973 const RefType * inst2= handleRefType( inst, other );974 if ( ! inst2) return;969 const XInstType * otherInst = handleRefType( inst, other ); 970 if ( ! this->result ) return; 975 971 976 972 // check that parameters of types unify, if any 977 973 const std::vector< ast::ptr< ast::Expr > > & params = inst->params; 978 const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;974 const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params; 979 975 980 976 auto it = params.begin(); … … 1032 1028 1033 1029 void postvisit( const ast::TypeInstType * typeInst ) { 1034 assert( open.find( typeInst->name) == open.end() );1030 assert( open.find( *typeInst ) == open.end() ); 1035 1031 handleRefType( typeInst, type2 ); 1036 1032 } … … 1038 1034 private: 1039 1035 /// Creates a tuple type based on a list of Type 1040 static ast::ptr< ast::Type >tupleFromTypes(1036 static const ast::Type * tupleFromTypes( 1041 1037 const std::vector< ast::ptr< ast::Type > > & tys 1042 1038 ) { … … 1114 1110 1115 1111 ast::Pass<TtypeExpander_new> expander{ tenv }; 1112 1116 1113 const ast::Type * flat = tuple->accept( expander ); 1117 1114 const ast::Type * flat2 = tuple2->accept( expander ); … … 1140 1137 }; 1141 1138 1139 // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new"); 1142 1140 bool unify( 1143 1141 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, … … 1171 1169 auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 ); 1172 1170 ast::OpenVarSet::const_iterator 1173 entry1 = var1 ? open.find( var1->name) : open.end(),1174 entry2 = var2 ? open.find( var2->name) : open.end();1171 entry1 = var1 ? open.find( *var1 ) : open.end(), 1172 entry2 = var2 ? open.find( *var2 ) : open.end(); 1175 1173 bool isopen1 = entry1 != open.end(); 1176 1174 bool isopen2 = entry2 != open.end(); … … 1188 1186 ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab }; 1189 1187 type1->accept( comparator ); 1190 return comparator. pass.result;1188 return comparator.core.result; 1191 1189 } 1192 1190 } … … 1202 1200 // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and 1203 1201 // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1 1204 ast::ptr<ast::Type> t1{ type1 }, t2{ type2 }; 1205 reset_qualifiers( t1 ); 1206 reset_qualifiers( t2 ); 1202 ast::Type * t1 = shallowCopy(type1.get()); 1203 ast::Type * t2 = shallowCopy(type2.get()); 1204 t1->qualifiers = {}; 1205 t2->qualifiers = {}; 1206 ast::ptr< ast::Type > t1_(t1); 1207 ast::ptr< ast::Type > t2_(t2); 1207 1208 1208 1209 if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) { 1209 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1210 1211 1210 // if exact unification on unqualified types, try to merge qualifiers 1212 1211 if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) { 1213 common = type1;1214 reset_qualifiers( common, q1 | q2 );1212 t1->qualifiers = q1 | q2; 1213 common = t1; 1215 1214 return true; 1216 1215 } else { … … 1219 1218 1220 1219 } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) { 1221 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1222 1223 1220 // no exact unification, but common type 1224 reset_qualifiers( common, q1 | q2 ); 1221 auto c = shallowCopy(common.get()); 1222 c->qualifiers = q1 | q2; 1223 common = c; 1225 1224 return true; 1226 1225 } else { … … 1231 1230 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) { 1232 1231 if ( func->returns.empty() ) return new ast::VoidType{}; 1233 if ( func->returns.size() == 1 ) return func->returns[0] ->get_type();1232 if ( func->returns.size() == 1 ) return func->returns[0]; 1234 1233 1235 1234 std::vector<ast::ptr<ast::Type>> tys; 1236 for ( const a st::DeclWithType *decl : func->returns ) {1237 tys.emplace_back( decl ->get_type());1235 for ( const auto & decl : func->returns ) { 1236 tys.emplace_back( decl ); 1238 1237 } 1239 1238 return new ast::TupleType{ std::move(tys) }; -
src/ResolvExpr/module.mk
rbdfc032 reef8dfb 19 19 ResolvExpr/Alternative.cc \ 20 20 ResolvExpr/AlternativeFinder.cc \ 21 ResolvExpr/AlternativeFinder.h \ 22 ResolvExpr/Alternative.h \ 21 23 ResolvExpr/Candidate.cpp \ 22 24 ResolvExpr/CandidateFinder.cpp \ 25 ResolvExpr/CandidateFinder.hpp \ 26 ResolvExpr/Candidate.hpp \ 23 27 ResolvExpr/CastCost.cc \ 24 28 ResolvExpr/CommonType.cc \ 25 29 ResolvExpr/ConversionCost.cc \ 30 ResolvExpr/ConversionCost.h \ 31 ResolvExpr/Cost.h \ 26 32 ResolvExpr/CurrentObject.cc \ 33 ResolvExpr/CurrentObject.h \ 27 34 ResolvExpr/ExplodedActual.cc \ 35 ResolvExpr/ExplodedActual.h \ 28 36 ResolvExpr/ExplodedArg.cpp \ 37 ResolvExpr/ExplodedArg.hpp \ 29 38 ResolvExpr/FindOpenVars.cc \ 39 ResolvExpr/FindOpenVars.h \ 30 40 ResolvExpr/Occurs.cc \ 31 41 ResolvExpr/PolyCost.cc \ … … 33 43 ResolvExpr/PtrsCastable.cc \ 34 44 ResolvExpr/RenameVars.cc \ 45 ResolvExpr/RenameVars.h \ 35 46 ResolvExpr/ResolveAssertions.cc \ 47 ResolvExpr/ResolveAssertions.h \ 36 48 ResolvExpr/Resolver.cc \ 49 ResolvExpr/Resolver.h \ 37 50 ResolvExpr/ResolveTypeof.cc \ 51 ResolvExpr/ResolveTypeof.h \ 52 ResolvExpr/ResolvMode.h \ 38 53 ResolvExpr/SatisfyAssertions.cpp \ 54 ResolvExpr/SatisfyAssertions.hpp \ 39 55 ResolvExpr/SpecCost.cc \ 40 56 ResolvExpr/TypeEnvironment.cc \ 41 ResolvExpr/Unify.cc 57 ResolvExpr/TypeEnvironment.h \ 58 ResolvExpr/typeops.h \ 59 ResolvExpr/Unify.cc \ 60 ResolvExpr/Unify.h \ 61 ResolvExpr/WidenMode.h 42 62 43 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc 63 64 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc ResolvExpr/AlternativePrinter.h 44 65 SRCDEMANGLE += $(SRC_RESOLVEXPR) -
src/ResolvExpr/typeops.h
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 07:28:22 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:36:00 201913 // Update Count : 512 // Last Modified On : Tue Oct 1 09:45:00 2019 13 // Update Count : 6 14 14 // 15 15 … … 83 83 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 84 84 Cost castCost( 85 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,86 const ast:: TypeEnvironment & env );85 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 86 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 87 87 88 88 // in ConversionCost.cc … … 90 90 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 91 91 Cost conversionCost( 92 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,93 const ast:: TypeEnvironment & env );92 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 93 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 94 94 95 95 // in AlternativeFinder.cc -
src/SymTab/Autogen.cc
rbdfc032 reef8dfb 38 38 #include "SynTree/Type.h" // for FunctionType, Type, TypeInstType 39 39 #include "SynTree/Visitor.h" // for maybeAccept, Visitor, acceptAll 40 #include "CompilationState.h" 40 41 41 42 class Attribute; … … 233 234 } 234 235 236 // shallow copy the pointer list for return 237 std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) { 238 if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) { 239 return structInst->base->params; 240 } 241 if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) { 242 return unionInst->base->params; 243 } 244 return {}; 245 } 246 235 247 /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *) 236 248 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) { … … 244 256 ftype->parameters.push_back( dstParam ); 245 257 return ftype; 258 } 259 260 /// 261 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) { 262 std::vector<ast::ptr<ast::TypeDecl>> typeParams; 263 if (maybePolymorphic) typeParams = getGenericParams(paramType); 264 auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall); 265 return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc)); 246 266 } 247 267 … … 327 347 void FuncGenerator::resolve( FunctionDecl * dcl ) { 328 348 try { 329 ResolvExpr::resolveDecl( dcl, indexer ); 349 if (!useNewAST) // attempt to delay resolver call 350 ResolvExpr::resolveDecl( dcl, indexer ); 330 351 if ( functionNesting == 0 ) { 331 352 // forward declare if top-level struct, so that … … 339 360 } catch ( SemanticErrorException & ) { 340 361 // okay if decl does not resolve - that means the function should not be generated 341 delete dcl; 362 // delete dcl; 363 delete dcl->statements; 364 dcl->statements = nullptr; 365 dcl->isDeleted = true; 366 definitions.push_back( dcl ); 367 indexer.addId( dcl ); 342 368 } 343 369 } -
src/SymTab/Autogen.h
rbdfc032 reef8dfb 21 21 22 22 #include "AST/Decl.hpp" 23 #include "AST/Eval.hpp" 23 24 #include "AST/Expr.hpp" 24 25 #include "AST/Init.hpp" … … 54 55 /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic 55 56 FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true ); 57 58 ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true); 56 59 57 60 /// generate the type of a copy constructor for paramType. … … 164 167 fExpr->args.emplace_back( dstParam ); 165 168 166 const ast::Stmt *listInit = srcParam.buildListInit( fExpr );169 ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr ); 167 170 168 171 // fetch next set of arguments … … 265 268 } 266 269 267 ast::ptr< ast::Expr > begin, end, cmp, update; 270 ast::ptr< ast::Expr > begin, end; 271 std::string cmp, update; 268 272 269 273 if ( forward ) { … … 271 275 begin = ast::ConstantExpr::from_int( loc, 0 ); 272 276 end = array->dimension; 273 cmp = new ast::NameExpr{ loc, "?<?" };274 update = new ast::NameExpr{ loc, "++?" };277 cmp = "?<?"; 278 update = "++?"; 275 279 } else { 276 280 // generate: for ( int i = N-1; i >= 0; --i ) 277 begin = new ast::UntypedExpr{ 278 loc, new ast::NameExpr{ loc, "?-?" }, 279 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } }; 281 begin = ast::call( 282 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) ); 280 283 end = ast::ConstantExpr::from_int( loc, 0 ); 281 cmp = new ast::NameExpr{ loc, "?>=?" };282 update = new ast::NameExpr{ loc, "--?" };284 cmp = "?>=?"; 285 update = "--?"; 283 286 } 284 287 … … 286 289 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 287 290 new ast::SingleInit{ loc, begin } }; 288 289 ast::ptr< ast::Expr > cond = new ast::UntypedExpr{ 290 loc, cmp, { new ast::VariableExpr{ loc, index }, end } }; 291 292 ast::ptr< ast::Expr > inc = new ast::UntypedExpr{ 293 loc, update, { new ast::VariableExpr{ loc, index } } }; 294 295 ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{ 296 loc, new ast::NameExpr{ loc, "?[?]" }, 297 { dstParam, new ast::VariableExpr{ loc, index } } }; 291 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index }; 292 293 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end ); 294 295 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar ); 296 297 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar ); 298 298 299 299 // srcParam must keep track of the array indices to build the source parameter and/or 300 300 // array list initializer 301 srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );301 srcParam.addArrayIndex( indexVar, array->dimension ); 302 302 303 303 // for stmt's body, eventually containing call … … 385 385 if ( isUnnamedBitfield( obj ) ) return {}; 386 386 387 ast::ptr< ast::Type > addCast = nullptr;387 ast::ptr< ast::Type > addCast; 388 388 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) { 389 389 assert( dstParam->result ); -
src/SymTab/Demangle.cc
rbdfc032 reef8dfb 10 10 // Created On : Thu Jul 19 12:52:41 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 14:54:15 201913 // Update Count : 412 // Last Modified On : Tue Feb 11 15:09:18 2020 13 // Update Count : 10 14 14 // 15 15 … … 19 19 #include "CodeGen/GenType.h" 20 20 #include "Common/PassVisitor.h" 21 #include "Common/utility.h" // isPrefix 21 22 #include "Mangler.h" 22 23 #include "SynTree/Type.h" … … 416 417 417 418 bool StringView::isPrefix(const std::string & pref) { 418 if ( pref.size() > str.size()-idx ) return false; 419 auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) ); 420 if (its.first == pref.end()) { 419 // if ( pref.size() > str.size()-idx ) return false; 420 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) ); 421 // if (its.first == pref.end()) { 422 // idx += pref.size(); 423 // return true; 424 // } 425 426 // This update is untested because there are no tests for this code. 427 if ( ::isPrefix( str, pref, idx ) ) { 421 428 idx += pref.size(); 422 429 return true; … … 429 436 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; ) 430 437 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix 431 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back())) return false;438 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false; 432 439 433 440 // get name -
src/SymTab/FixFunction.cc
rbdfc032 reef8dfb 106 106 bool isVoid = false; 107 107 108 void pre mutate( const ast::FunctionDecl * ) { visit_children = false; }108 void previsit( const ast::FunctionDecl * ) { visit_children = false; } 109 109 110 const ast::DeclWithType * post mutate( const ast::FunctionDecl * func ) {110 const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) { 111 111 return new ast::ObjectDecl{ 112 112 func->location, func->name, new ast::PointerType{ func->type }, nullptr, … … 114 114 } 115 115 116 void pre mutate( const ast::ArrayType * ) { visit_children = false; }116 void previsit( const ast::ArrayType * ) { visit_children = false; } 117 117 118 const ast::Type * post mutate( const ast::ArrayType * array ) {118 const ast::Type * postvisit( const ast::ArrayType * array ) { 119 119 return new ast::PointerType{ 120 120 array->base, array->dimension, array->isVarLen, array->isStatic, … … 122 122 } 123 123 124 void pre mutate( const ast::VoidType * ) { isVoid = true; }124 void previsit( const ast::VoidType * ) { isVoid = true; } 125 125 126 void pre mutate( const ast::BasicType * ) { visit_children = false; }127 void pre mutate( const ast::PointerType * ) { visit_children = false; }128 void pre mutate( const ast::StructInstType * ) { visit_children = false; }129 void pre mutate( const ast::UnionInstType * ) { visit_children = false; }130 void pre mutate( const ast::EnumInstType * ) { visit_children = false; }131 void pre mutate( const ast::TraitInstType * ) { visit_children = false; }132 void pre mutate( const ast::TypeInstType * ) { visit_children = false; }133 void pre mutate( const ast::TupleType * ) { visit_children = false; }134 void pre mutate( const ast::VarArgsType * ) { visit_children = false; }135 void pre mutate( const ast::ZeroType * ) { visit_children = false; }136 void pre mutate( const ast::OneType * ) { visit_children = false; }126 void previsit( const ast::BasicType * ) { visit_children = false; } 127 void previsit( const ast::PointerType * ) { visit_children = false; } 128 void previsit( const ast::StructInstType * ) { visit_children = false; } 129 void previsit( const ast::UnionInstType * ) { visit_children = false; } 130 void previsit( const ast::EnumInstType * ) { visit_children = false; } 131 void previsit( const ast::TraitInstType * ) { visit_children = false; } 132 void previsit( const ast::TypeInstType * ) { visit_children = false; } 133 void previsit( const ast::TupleType * ) { visit_children = false; } 134 void previsit( const ast::VarArgsType * ) { visit_children = false; } 135 void previsit( const ast::ZeroType * ) { visit_children = false; } 136 void previsit( const ast::OneType * ) { visit_children = false; } 137 137 }; 138 138 } // anonymous namespace … … 141 141 ast::Pass< FixFunction_new > fixer; 142 142 dwt = dwt->accept( fixer ); 143 isVoid |= fixer. pass.isVoid;143 isVoid |= fixer.core.isVoid; 144 144 return dwt; 145 145 } -
src/SymTab/Mangler.cc
rbdfc032 reef8dfb 10 10 // Created On : Sun May 17 21:40:29 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:43:49 201913 // Update Count : 2812 // Last Modified On : Wed Nov 18 12:01:38 2020 13 // Update Count : 64 14 14 // 15 15 #include "Mangler.h" … … 65 65 void postvisit( const QualifiedType * qualType ); 66 66 67 std::string get_mangleName() { return mangleName .str(); }67 std::string get_mangleName() { return mangleName; } 68 68 private: 69 std:: ostringstream mangleName;///< Mangled name being constructed69 std::string mangleName; ///< Mangled name being constructed 70 70 typedef std::map< std::string, std::pair< int, int > > VarMapType; 71 71 VarMapType varNums; ///< Map of type variables to indices … … 127 127 isTopLevel = false; 128 128 } // if 129 mangleName <<Encoding::manglePrefix;130 CodeGen::OperatorInfo opInfo;131 if ( op eratorLookup( declaration->get_name(), opInfo )) {132 mangleName << opInfo.outputName.size() << opInfo.outputName;129 mangleName += Encoding::manglePrefix; 130 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() ); 131 if ( opInfo ) { 132 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName; 133 133 } else { 134 mangleName << declaration->name.size() <<declaration->name;134 mangleName += std::to_string( declaration->name.size() ) + declaration->name; 135 135 } // if 136 136 maybeAccept( declaration->get_type(), *visitor ); … … 139 139 // so they need a different name mangling 140 140 if ( declaration->get_linkage() == LinkageSpec::AutoGen ) { 141 mangleName <<Encoding::autogen;141 mangleName += Encoding::autogen; 142 142 } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) { 143 mangleName <<Encoding::intrinsic;143 mangleName += Encoding::intrinsic; 144 144 } else { 145 145 // if we add another kind of overridable function, this has to change … … 160 160 void Mangler_old::postvisit( const VoidType * voidType ) { 161 161 printQualifiers( voidType ); 162 mangleName <<Encoding::void_t;162 mangleName += Encoding::void_t; 163 163 } 164 164 … … 166 166 printQualifiers( basicType ); 167 167 assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind ); 168 mangleName <<Encoding::basicTypes[ basicType->kind ];168 mangleName += Encoding::basicTypes[ basicType->kind ]; 169 169 } 170 170 … … 172 172 printQualifiers( pointerType ); 173 173 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers 174 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName <<Encoding::pointer;174 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer; 175 175 maybeAccept( pointerType->base, *visitor ); 176 176 } … … 179 179 // TODO: encode dimension 180 180 printQualifiers( arrayType ); 181 mangleName << Encoding::array <<"0";181 mangleName += Encoding::array + "0"; 182 182 maybeAccept( arrayType->base, *visitor ); 183 183 } … … 204 204 void Mangler_old::postvisit( const FunctionType * functionType ) { 205 205 printQualifiers( functionType ); 206 mangleName <<Encoding::function;206 mangleName += Encoding::function; 207 207 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters, 208 208 // since qualifiers on outermost parameter type do not differentiate function types, e.g., … … 211 211 inFunctionType = true; 212 212 std::list< Type* > returnTypes = getTypes( functionType->returnVals ); 213 if (returnTypes.empty()) mangleName <<Encoding::void_t;213 if (returnTypes.empty()) mangleName += Encoding::void_t; 214 214 else acceptAll( returnTypes, *visitor ); 215 mangleName <<"_";215 mangleName += "_"; 216 216 std::list< Type* > paramTypes = getTypes( functionType->parameters ); 217 217 acceptAll( paramTypes, *visitor ); 218 mangleName <<"_";218 mangleName += "_"; 219 219 } 220 220 … … 222 222 printQualifiers( refType ); 223 223 224 mangleName << prefix << refType->name.length() <<refType->name;224 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name; 225 225 226 226 if ( mangleGenericParams ) { 227 227 const std::list< Expression* > & params = refType->parameters; 228 228 if ( ! params.empty() ) { 229 mangleName <<"_";229 mangleName += "_"; 230 230 for ( const Expression * param : params ) { 231 231 const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param ); … … 233 233 maybeAccept( paramType->type, *visitor ); 234 234 } 235 mangleName <<"_";235 mangleName += "_"; 236 236 } 237 237 } … … 262 262 // are first found and prefixing with the appropriate encoding for the type class. 263 263 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second ); 264 mangleName << Encoding::typeVariables[varNum->second.second] << varNum->second.first;264 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first ); 265 265 } // if 266 266 } … … 268 268 void Mangler_old::postvisit( const TraitInstType * inst ) { 269 269 printQualifiers( inst ); 270 mangleName << inst->name.size() <<inst->name;270 mangleName += std::to_string( inst->name.size() ) + inst->name; 271 271 } 272 272 273 273 void Mangler_old::postvisit( const TupleType * tupleType ) { 274 274 printQualifiers( tupleType ); 275 mangleName << Encoding::tuple << tupleType->types.size();275 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() ); 276 276 acceptAll( tupleType->types, *visitor ); 277 277 } … … 280 280 printQualifiers( varArgsType ); 281 281 static const std::string vargs = "__builtin_va_list"; 282 mangleName << Encoding::type << vargs.size() <<vargs;282 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs; 283 283 } 284 284 285 285 void Mangler_old::postvisit( const ZeroType * ) { 286 mangleName <<Encoding::zero;286 mangleName += Encoding::zero; 287 287 } 288 288 289 289 void Mangler_old::postvisit( const OneType * ) { 290 mangleName <<Encoding::one;290 mangleName += Encoding::one; 291 291 } 292 292 … … 296 296 // N marks the start of a qualified type 297 297 inQualifiedType = true; 298 mangleName <<Encoding::qualifiedTypeStart;298 mangleName += Encoding::qualifiedTypeStart; 299 299 } 300 300 maybeAccept( qualType->parent, *visitor ); … … 303 303 // E marks the end of a qualified type 304 304 inQualifiedType = false; 305 mangleName <<Encoding::qualifiedTypeEnd;305 mangleName += Encoding::qualifiedTypeEnd; 306 306 } 307 307 } … … 315 315 assertf(false, "Mangler_old should not visit typedecl: %s", toCString(decl)); 316 316 assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind ); 317 mangleName << Encoding::typeVariables[ decl->kind ] << ( decl->name.length() ) <<decl->name;317 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name; 318 318 } 319 319 … … 330 330 std::list< std::string > assertionNames; 331 331 int dcount = 0, fcount = 0, vcount = 0, acount = 0; 332 mangleName <<Encoding::forall;332 mangleName += Encoding::forall; 333 333 for ( const TypeDecl * i : type->forall ) { 334 334 switch ( i->kind ) { … … 354 354 } // for 355 355 } // for 356 mangleName << dcount << "_" << fcount << "_" << vcount << "_" << acount << "_"; 357 std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) ); 358 mangleName << "_"; 356 mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_"; 357 for(const auto & a : assertionNames) mangleName += a; 358 // std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) ); 359 mangleName += "_"; 359 360 } // if 360 361 if ( ! inFunctionType ) { 361 362 // these qualifiers do not distinguish the outermost type of a function parameter 362 363 if ( type->get_const() ) { 363 mangleName <<Encoding::qualifiers.at(Type::Const);364 mangleName += Encoding::qualifiers.at(Type::Const); 364 365 } // if 365 366 if ( type->get_volatile() ) { 366 mangleName <<Encoding::qualifiers.at(Type::Volatile);367 mangleName += Encoding::qualifiers.at(Type::Volatile); 367 368 } // if 368 369 // Removed due to restrict not affecting function compatibility in GCC 369 370 // if ( type->get_isRestrict() ) { 370 // mangleName <<"E";371 // mangleName += "E"; 371 372 // } // if 372 373 if ( type->get_atomic() ) { 373 mangleName <<Encoding::qualifiers.at(Type::Atomic);374 mangleName += Encoding::qualifiers.at(Type::Atomic); 374 375 } // if 375 376 } 376 377 if ( type->get_mutex() ) { 377 mangleName <<Encoding::qualifiers.at(Type::Mutex);378 mangleName += Encoding::qualifiers.at(Type::Mutex); 378 379 } // if 379 380 if ( inFunctionType ) { … … 383 384 } 384 385 } 385 } 386 } // namespace 386 387 } // namespace Mangler 387 388 } // namespace SymTab … … 417 418 void postvisit( const ast::QualifiedType * qualType ); 418 419 419 std::string get_mangleName() { return mangleName .str(); }420 std::string get_mangleName() { return mangleName; } 420 421 private: 421 std:: ostringstream mangleName;///< Mangled name being constructed422 std::string mangleName; ///< Mangled name being constructed 422 423 typedef std::map< std::string, std::pair< int, int > > VarMapType; 423 424 VarMapType varNums; ///< Map of type variables to indices … … 437 438 private: 438 439 void mangleDecl( const ast::DeclWithType *declaration ); 439 void mangleRef( const ast:: ReferenceToType *refType, std::string prefix );440 void mangleRef( const ast::BaseInstType *refType, std::string prefix ); 440 441 441 442 void printQualifiers( const ast::Type *type ); … … 447 448 ast::Pass<Mangler_new> mangler( mode ); 448 449 maybeAccept( decl, mangler ); 449 return mangler. pass.get_mangleName();450 return mangler.core.get_mangleName(); 450 451 } 451 452 … … 470 471 isTopLevel = false; 471 472 } // if 472 mangleName <<Encoding::manglePrefix;473 CodeGen::OperatorInfo opInfo;474 if ( op eratorLookup( decl->name, opInfo )) {475 mangleName << opInfo.outputName.size() << opInfo.outputName;473 mangleName += Encoding::manglePrefix; 474 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name ); 475 if ( opInfo ) { 476 mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName; 476 477 } else { 477 mangleName << decl->name.size() <<decl->name;478 mangleName += std::to_string( decl->name.size() ) + decl->name; 478 479 } // if 479 480 maybeAccept( decl->get_type(), *visitor ); … … 482 483 // so they need a different name mangling 483 484 if ( decl->linkage == ast::Linkage::AutoGen ) { 484 mangleName <<Encoding::autogen;485 mangleName += Encoding::autogen; 485 486 } else if ( decl->linkage == ast::Linkage::Intrinsic ) { 486 mangleName <<Encoding::intrinsic;487 mangleName += Encoding::intrinsic; 487 488 } else { 488 489 // if we add another kind of overridable function, this has to change … … 503 504 void Mangler_new::postvisit( const ast::VoidType * voidType ) { 504 505 printQualifiers( voidType ); 505 mangleName <<Encoding::void_t;506 mangleName += Encoding::void_t; 506 507 } 507 508 … … 509 510 printQualifiers( basicType ); 510 511 assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind ); 511 mangleName <<Encoding::basicTypes[ basicType->kind ];512 mangleName += Encoding::basicTypes[ basicType->kind ]; 512 513 } 513 514 … … 515 516 printQualifiers( pointerType ); 516 517 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers 517 if ( ! pointerType->base.as<ast::FunctionType>() ) mangleName <<Encoding::pointer;518 if ( ! pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer; 518 519 maybe_accept( pointerType->base.get(), *visitor ); 519 520 } … … 522 523 // TODO: encode dimension 523 524 printQualifiers( arrayType ); 524 mangleName << Encoding::array <<"0";525 mangleName += Encoding::array + "0"; 525 526 maybeAccept( arrayType->base.get(), *visitor ); 526 527 } … … 545 546 void Mangler_new::postvisit( const ast::FunctionType * functionType ) { 546 547 printQualifiers( functionType ); 547 mangleName <<Encoding::function;548 mangleName += Encoding::function; 548 549 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters, 549 550 // since qualifiers on outermost parameter type do not differentiate function types, e.g., … … 551 552 GuardValue( inFunctionType ); 552 553 inFunctionType = true; 553 std::vector< ast::ptr< ast::Type > > returnTypes = getTypes( functionType->returns ); 554 if (returnTypes.empty()) mangleName << Encoding::void_t; 555 else accept_each( returnTypes, *visitor ); 556 mangleName << "_"; 557 std::vector< ast::ptr< ast::Type > > paramTypes = getTypes( functionType->params ); 558 accept_each( paramTypes, *visitor ); 559 mangleName << "_"; 560 } 561 562 void Mangler_new::mangleRef( const ast::ReferenceToType * refType, std::string prefix ) { 554 if (functionType->returns.empty()) mangleName += Encoding::void_t; 555 else accept_each( functionType->returns, *visitor ); 556 mangleName += "_"; 557 accept_each( functionType->params, *visitor ); 558 mangleName += "_"; 559 } 560 561 void Mangler_new::mangleRef( const ast::BaseInstType * refType, std::string prefix ) { 563 562 printQualifiers( refType ); 564 563 565 mangleName << prefix << refType->name.length() <<refType->name;564 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name; 566 565 567 566 if ( mangleGenericParams ) { 568 567 if ( ! refType->params.empty() ) { 569 mangleName <<"_";568 mangleName += "_"; 570 569 for ( const ast::Expr * param : refType->params ) { 571 570 auto paramType = dynamic_cast< const ast::TypeExpr * >( param ); … … 573 572 maybeAccept( paramType->type.get(), *visitor ); 574 573 } 575 mangleName <<"_";574 mangleName += "_"; 576 575 } 577 576 } … … 602 601 // are first found and prefixing with the appropriate encoding for the type class. 603 602 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second ); 604 mangleName << Encoding::typeVariables[varNum->second.second] << varNum->second.first;603 mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first ); 605 604 } // if 606 605 } … … 608 607 void Mangler_new::postvisit( const ast::TraitInstType * inst ) { 609 608 printQualifiers( inst ); 610 mangleName << inst->name.size() <<inst->name;609 mangleName += std::to_string( inst->name.size() ) + inst->name; 611 610 } 612 611 613 612 void Mangler_new::postvisit( const ast::TupleType * tupleType ) { 614 613 printQualifiers( tupleType ); 615 mangleName << Encoding::tuple << tupleType->types.size();614 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() ); 616 615 accept_each( tupleType->types, *visitor ); 617 616 } … … 620 619 printQualifiers( varArgsType ); 621 620 static const std::string vargs = "__builtin_va_list"; 622 mangleName << Encoding::type << vargs.size() <<vargs;621 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs; 623 622 } 624 623 625 624 void Mangler_new::postvisit( const ast::ZeroType * ) { 626 mangleName <<Encoding::zero;625 mangleName += Encoding::zero; 627 626 } 628 627 629 628 void Mangler_new::postvisit( const ast::OneType * ) { 630 mangleName <<Encoding::one;629 mangleName += Encoding::one; 631 630 } 632 631 … … 636 635 // N marks the start of a qualified type 637 636 inQualifiedType = true; 638 mangleName <<Encoding::qualifiedTypeStart;637 mangleName += Encoding::qualifiedTypeStart; 639 638 } 640 639 maybeAccept( qualType->parent.get(), *visitor ); … … 643 642 // E marks the end of a qualified type 644 643 inQualifiedType = false; 645 mangleName <<Encoding::qualifiedTypeEnd;644 mangleName += Encoding::qualifiedTypeEnd; 646 645 } 647 646 } … … 655 654 assertf(false, "Mangler_new should not visit typedecl: %s", toCString(decl)); 656 655 assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind ); 657 mangleName << Encoding::typeVariables[ decl->kind ] << ( decl->name.length() ) <<decl->name;656 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name; 658 657 } 659 658 … … 667 666 // skip if not including qualifiers 668 667 if ( typeMode ) return; 669 if ( auto ptype = dynamic_cast< const ast:: ParameterizedType * >(type) ) {668 if ( auto ptype = dynamic_cast< const ast::FunctionType * >(type) ) { 670 669 if ( ! ptype->forall.empty() ) { 671 670 std::list< std::string > assertionNames; 672 671 int dcount = 0, fcount = 0, vcount = 0, acount = 0; 673 mangleName <<Encoding::forall;674 for ( const ast::TypeDecl *decl : ptype->forall ) {672 mangleName += Encoding::forall; 673 for ( auto & decl : ptype->forall ) { 675 674 switch ( decl->kind ) { 676 675 case ast::TypeDecl::Kind::Dtype: … … 687 686 } // switch 688 687 varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind ); 689 for ( const ast::DeclWithType * assert : decl->assertions ) {690 ast::Pass<Mangler_new> sub_mangler(691 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );692 assert->accept( sub_mangler );693 assertionNames.push_back( sub_mangler.pass.get_mangleName() );694 acount++;695 } // for696 688 } // for 697 mangleName << dcount << "_" << fcount << "_" << vcount << "_" << acount << "_"; 698 std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) ); 699 mangleName << "_"; 689 for ( auto & assert : ptype->assertions ) { 690 ast::Pass<Mangler_new> sub_mangler( 691 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ); 692 assert->var->accept( sub_mangler ); 693 assertionNames.push_back( sub_mangler.core.get_mangleName() ); 694 acount++; 695 } // for 696 mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_"; 697 for(const auto & a : assertionNames) mangleName += a; 698 // std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) ); 699 mangleName += "_"; 700 700 } // if 701 701 } // if … … 703 703 // these qualifiers do not distinguish the outermost type of a function parameter 704 704 if ( type->is_const() ) { 705 mangleName <<Encoding::qualifiers.at(Type::Const);705 mangleName += Encoding::qualifiers.at(Type::Const); 706 706 } // if 707 707 if ( type->is_volatile() ) { 708 mangleName <<Encoding::qualifiers.at(Type::Volatile);708 mangleName += Encoding::qualifiers.at(Type::Volatile); 709 709 } // if 710 710 // Removed due to restrict not affecting function compatibility in GCC 711 711 // if ( type->get_isRestrict() ) { 712 // mangleName <<"E";712 // mangleName += "E"; 713 713 // } // if 714 714 if ( type->is_atomic() ) { 715 mangleName <<Encoding::qualifiers.at(Type::Atomic);715 mangleName += Encoding::qualifiers.at(Type::Atomic); 716 716 } // if 717 717 } 718 718 if ( type->is_mutex() ) { 719 mangleName <<Encoding::qualifiers.at(Type::Mutex);719 mangleName += Encoding::qualifiers.at(Type::Mutex); 720 720 } // if 721 721 if ( inFunctionType ) { -
src/SymTab/Validate.cc
rbdfc032 reef8dfb 64 64 #include "Common/UniqueName.h" // for UniqueName 65 65 #include "Common/utility.h" // for operator+, cloneAll, deleteAll 66 #include "CompilationState.h" // skip some passes in new-ast build 66 67 #include "Concurrency/Keywords.h" // for applyKeywords 67 68 #include "FixFunction.h" // for FixFunction … … 270 271 }; 271 272 272 struct ArrayLength : public WithIndexer{273 struct InitializerLength { 273 274 /// for array types without an explicit length, compute the length and store it so that it 274 275 /// is known to the rest of the phases. For example, … … 281 282 282 283 void previsit( ObjectDecl * objDecl ); 284 }; 285 286 struct ArrayLength : public WithIndexer { 287 static void computeLength( std::list< Declaration * > & translationUnit ); 288 283 289 void previsit( ArrayType * arrayType ); 284 290 }; … … 311 317 Stats::Heap::newPass("validate-A"); 312 318 Stats::Time::BlockGuard guard("validate-A"); 319 VerifyCtorDtorAssign::verify( translationUnit ); // must happen before autogen, because autogen examines existing ctor/dtors 313 320 acceptAll( translationUnit, hoistDecls ); 314 321 ReplaceTypedef::replaceTypedef( translationUnit ); … … 336 343 Stats::Time::BlockGuard guard("validate-C"); 337 344 acceptAll( translationUnit, genericParams ); // check as early as possible - can't happen before LinkReferenceToTypes_old 338 VerifyCtorDtorAssign::verify( translationUnit ); // must happen before autogen, because autogen examines existing ctor/dtors339 345 ReturnChecker::checkFunctionReturns( translationUnit ); 340 346 InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen … … 368 374 mutateAll( translationUnit, compoundliteral ); 369 375 }); 370 Stats::Time::TimeBlock("Resolve With Expressions", [&]() { 371 ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables 372 }); 376 if (!useNewAST) { 377 Stats::Time::TimeBlock("Resolve With Expressions", [&]() { 378 ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables 379 }); 380 } 373 381 } 374 382 { 375 383 Stats::Heap::newPass("validate-F"); 376 384 Stats::Time::BlockGuard guard("validate-F"); 377 Stats::Time::TimeCall("Fix Object Type", 378 FixObjectType::fix, translationUnit); 379 Stats::Time::TimeCall("Array Length", 380 ArrayLength::computeLength, translationUnit); 385 if (!useNewAST) { 386 Stats::Time::TimeCall("Fix Object Type", 387 FixObjectType::fix, translationUnit); 388 } 389 Stats::Time::TimeCall("Initializer Length", 390 InitializerLength::computeLength, translationUnit); 391 if (!useNewAST) { 392 Stats::Time::TimeCall("Array Length", 393 ArrayLength::computeLength, translationUnit); 394 } 381 395 Stats::Time::TimeCall("Find Special Declarations", 382 396 Validate::findSpecialDecls, translationUnit); 383 397 Stats::Time::TimeCall("Fix Label Address", 384 398 mutateAll<LabelAddressFixer>, translationUnit, labelAddrFixer); 385 Stats::Time::TimeCall("Handle Attributes", 386 Validate::handleAttributes, translationUnit); 399 if (!useNewAST) { 400 Stats::Time::TimeCall("Handle Attributes", 401 Validate::handleAttributes, translationUnit); 402 } 387 403 } 388 404 } … … 960 976 } 961 977 978 static bool isNonParameterAttribute( Attribute * attr ) { 979 static const std::vector<std::string> bad_names = { 980 "aligned", "__aligned__", 981 }; 982 for ( auto name : bad_names ) { 983 if ( name == attr->name ) { 984 return true; 985 } 986 } 987 return false; 988 } 989 962 990 Type * ReplaceTypedef::postmutate( TypeInstType * typeInst ) { 963 991 // instances of typedef types will come here. If it is an instance … … 968 996 ret->location = typeInst->location; 969 997 ret->get_qualifiers() |= typeInst->get_qualifiers(); 970 // attributes are not carried over from typedef to function parameters/return values 971 if ( ! inFunctionType ) { 972 ret->attributes.splice( ret->attributes.end(), typeInst->attributes ); 973 } else { 974 deleteAll( ret->attributes ); 975 ret->attributes.clear(); 976 } 998 // GCC ignores certain attributes if they arrive by typedef, this mimics that. 999 if ( inFunctionType ) { 1000 ret->attributes.remove_if( isNonParameterAttribute ); 1001 } 1002 ret->attributes.splice( ret->attributes.end(), typeInst->attributes ); 977 1003 // place instance parameters on the typedef'd type 978 1004 if ( ! typeInst->parameters.empty() ) { … … 1182 1208 if ( CodeGen::isCtorDtorAssign( funcDecl->get_name() ) ) { // TODO: also check /=, etc. 1183 1209 if ( params.size() == 0 ) { 1184 SemanticError( funcDecl , "Constructors, destructors, and assignment functions require at least one parameter" );1210 SemanticError( funcDecl->location, "Constructors, destructors, and assignment functions require at least one parameter." ); 1185 1211 } 1186 1212 ReferenceType * refType = dynamic_cast< ReferenceType * >( params.front()->get_type() ); 1187 1213 if ( ! refType ) { 1188 SemanticError( funcDecl , "First parameter of a constructor, destructor, or assignment function must be a reference" );1214 SemanticError( funcDecl->location, "First parameter of a constructor, destructor, or assignment function must be a reference." ); 1189 1215 } 1190 1216 if ( CodeGen::isCtorDtor( funcDecl->get_name() ) && returnVals.size() != 0 ) { 1191 SemanticError( funcDecl, "Constructors and destructors cannot have explicit return values " ); 1217 if(!returnVals.front()->get_type()->isVoid()) { 1218 SemanticError( funcDecl->location, "Constructors and destructors cannot have explicit return values." ); 1219 } 1192 1220 } 1193 1221 } … … 1313 1341 } 1314 1342 1343 void InitializerLength::computeLength( std::list< Declaration * > & translationUnit ) { 1344 PassVisitor<InitializerLength> len; 1345 acceptAll( translationUnit, len ); 1346 } 1347 1315 1348 void ArrayLength::computeLength( std::list< Declaration * > & translationUnit ) { 1316 1349 PassVisitor<ArrayLength> len; … … 1318 1351 } 1319 1352 1320 void ArrayLength::previsit( ObjectDecl * objDecl ) {1353 void InitializerLength::previsit( ObjectDecl * objDecl ) { 1321 1354 if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->type ) ) { 1322 1355 if ( at->dimension ) return; … … 1372 1405 /// Replaces enum types by int, and function/array types in function parameter and return 1373 1406 /// lists by appropriate pointers 1407 /* 1374 1408 struct EnumAndPointerDecay_new { 1375 1409 const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) { … … 1422 1456 } 1423 1457 }; 1458 */ 1424 1459 1425 1460 /// expand assertions from a trait instance, performing appropriate type variable substitutions … … 1440 1475 } 1441 1476 1477 /* 1478 1442 1479 /// Associates forward declarations of aggregates with their definitions 1443 1480 class LinkReferenceToTypes_new final … … 1506 1543 } 1507 1544 1508 void checkGenericParameters( const ast:: ReferenceToType * inst ) {1545 void checkGenericParameters( const ast::BaseInstType * inst ) { 1509 1546 for ( const ast::Expr * param : inst->params ) { 1510 1547 if ( ! dynamic_cast< const ast::TypeExpr * >( param ) ) { … … 1770 1807 static const node_t * forallFixer( 1771 1808 const CodeLocation & loc, const node_t * node, 1772 ast:: ParameterizedType::ForallList parent_t::* forallField1809 ast::FunctionType::ForallList parent_t::* forallField 1773 1810 ) { 1774 1811 for ( unsigned i = 0; i < (node->* forallField).size(); ++i ) { … … 1821 1858 } 1822 1859 }; 1860 */ 1823 1861 } // anonymous namespace 1824 1862 1863 /* 1825 1864 const ast::Type * validateType( 1826 1865 const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) { 1827 ast::Pass< EnumAndPointerDecay_new > epc;1866 // ast::Pass< EnumAndPointerDecay_new > epc; 1828 1867 ast::Pass< LinkReferenceToTypes_new > lrt{ loc, symtab }; 1829 1868 ast::Pass< ForallPointerDecay_new > fpd{ loc }; 1830 1869 1831 return type->accept( epc )->accept(lrt )->accept( fpd );1870 return type->accept( lrt )->accept( fpd ); 1832 1871 } 1872 */ 1833 1873 1834 1874 } // namespace SymTab -
src/SymTab/module.mk
rbdfc032 reef8dfb 17 17 SRC_SYMTAB = \ 18 18 SymTab/Autogen.cc \ 19 SymTab/Autogen.h \ 19 20 SymTab/FixFunction.cc \ 21 SymTab/FixFunction.h \ 20 22 SymTab/Indexer.cc \ 23 SymTab/Indexer.h \ 21 24 SymTab/Mangler.cc \ 22 25 SymTab/ManglerCommon.cc \ 23 SymTab/Validate.cc 26 SymTab/Mangler.h \ 27 SymTab/Validate.cc \ 28 SymTab/Validate.h 24 29 25 30 SRC += $(SRC_SYMTAB) -
src/SynTree/AggregateDecl.cc
rbdfc032 reef8dfb 21 21 #include "Common/utility.h" // for printAll, cloneAll, deleteAll 22 22 #include "Declaration.h" // for AggregateDecl, TypeDecl, Declaration 23 #include "Expression.h" 23 24 #include "Initializer.h" 24 25 #include "LinkageSpec.h" // for Spec, linkageName, Cforall … … 88 89 const char * StructDecl::typeString() const { return aggrString( kind ); } 89 90 91 StructInstType * StructDecl::makeInst( std::list< Expression * > const & new_parameters ) { 92 std::list< Expression * > copy_parameters; 93 cloneAll( new_parameters, copy_parameters ); 94 return makeInst( move( copy( copy_parameters ) ) ); 95 } 96 97 StructInstType * StructDecl::makeInst( std::list< Expression * > && new_parameters ) { 98 assert( parameters.size() == new_parameters.size() ); 99 StructInstType * type = new StructInstType( noQualifiers, this ); 100 type->parameters = std::move( new_parameters ); 101 return type; 102 } 103 90 104 const char * UnionDecl::typeString() const { return aggrString( Union ); } 91 105 -
src/SynTree/ApplicationExpr.cc
rbdfc032 reef8dfb 34 34 35 35 ParamEntry::ParamEntry( const ParamEntry &other ) : 36 decl( other.decl ), declptr( maybeClone( other.declptr )), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {36 decl( other.decl ), declptr( other.declptr ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) { 37 37 } 38 38 39 39 ParamEntry::~ParamEntry() { 40 delete declptr;40 // delete declptr; 41 41 delete actualType; 42 42 delete formalType; -
src/SynTree/Attribute.h
rbdfc032 reef8dfb 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Jul 22 09:54:14 201713 // Update Count : 3912 // Last Modified On : Thu Feb 13 21:34:08 2020 13 // Update Count : 40 14 14 // 15 15 … … 38 38 virtual ~Attribute(); 39 39 40 std::stringget_name() const { return name; }40 const std::string & get_name() const { return name; } 41 41 void set_name( const std::string & newValue ) { name = newValue; } 42 42 std::list< Expression * > & get_parameters() { return parameters; } -
src/SynTree/Declaration.h
rbdfc032 reef8dfb 181 181 public: 182 182 Type * base; 183 std::list< TypeDecl * > parameters;184 183 std::list< DeclarationWithType * > assertions; 185 184 … … 190 189 Type * get_base() const { return base; } 191 190 void set_base( Type * newValue ) { base = newValue; } 192 std::list< TypeDecl* > & get_parameters() { return parameters; }193 191 std::list< DeclarationWithType * >& get_assertions() { return assertions; } 194 192 … … 302 300 303 301 bool is_coroutine() { return kind == Coroutine; } 304 bool is_monitor() { return kind == Monitor; } 305 bool is_thread() { return kind == Thread; } 302 bool is_generator() { return kind == Generator; } 303 bool is_monitor () { return kind == Monitor ; } 304 bool is_thread () { return kind == Thread ; } 305 306 // Make a type instance of this declaration. 307 StructInstType * makeInst( std::list< Expression * > const & parameters ); 308 StructInstType * makeInst( std::list< Expression * > && parameters ); 306 309 307 310 virtual StructDecl * clone() const override { return new StructDecl( *this ); } -
src/SynTree/Expression.cc
rbdfc032 reef8dfb 30 30 #include "Type.h" // for Type, BasicType, Type::Qualifiers 31 31 #include "TypeSubstitution.h" // for TypeSubstitution 32 #include "CompilationState.h" // for deterministic_output 32 33 33 34 #include "GenPoly/Lvalue.h" … … 70 71 printInferParams( inferParams, os, indent+1, 0 ); 71 72 73 if ( result ) { 74 os << std::endl << indent << "with resolved type:" << std::endl; 75 os << (indent+1); 76 result->print( os, indent+1 ); 77 } 78 72 79 if ( env ) { 73 80 os << std::endl << indent << "... with environment:" << std::endl; … … 293 300 } 294 301 295 KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) { 296 } 297 298 KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) { 299 } 302 KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {} 303 KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target, const KeywordCastExpr::Concrete & concrete_target ) : Expression(), arg(arg), target( target ), concrete_target(concrete_target) {} 304 305 KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {} 300 306 301 307 KeywordCastExpr::~KeywordCastExpr() { -
src/SynTree/Expression.h
rbdfc032 reef8dfb 163 163 }; 164 164 165 /// VariableExpr represents an expression that simply refers to the value of a named variable. 166 /// Does not take ownership of var. 167 class VariableExpr : public Expression { 168 public: 169 DeclarationWithType * var; 170 171 VariableExpr(); 172 VariableExpr( DeclarationWithType * var ); 173 VariableExpr( const VariableExpr & other ); 174 virtual ~VariableExpr(); 175 176 bool get_lvalue() const final; 177 178 DeclarationWithType * get_var() const { return var; } 179 void set_var( DeclarationWithType * newValue ) { var = newValue; } 180 181 static VariableExpr * functionPointer( FunctionDecl * decl ); 182 183 virtual VariableExpr * clone() const override { return new VariableExpr( * this ); } 184 virtual void accept( Visitor & v ) override { v.visit( this ); } 185 virtual void accept( Visitor & v ) const override { v.visit( this ); } 186 virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 187 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 188 }; 189 165 190 // The following classes are used to represent expression types that cannot be converted into 166 191 // function-call format. … … 206 231 public: 207 232 Expression * arg; 208 bool isGenerated = true; // cast generated implicitly by code generation or explicit in program 233 234 // Inidicates cast is introduced by the CFA type system. 235 // true for casts that the resolver introduces to force a return type 236 // false for casts from user code 237 // false for casts from desugaring advanced CFA features into simpler CFA 238 // example 239 // int * p; // declaration 240 // (float *) p; // use, with subject cast 241 // subject cast isGenerated means we are considering an interpretation with a type mismatch 242 // subject cast not isGenerated means someone in charge wants it that way 243 bool isGenerated = true; 209 244 210 245 CastExpr( Expression * arg, bool isGenerated = true ); … … 238 273 239 274 KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ); 275 KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target, const Concrete & concrete_target ); 240 276 KeywordCastExpr( const KeywordCastExpr & other ); 241 277 virtual ~KeywordCastExpr(); … … 312 348 313 349 virtual MemberExpr * clone() const override { return new MemberExpr( * this ); } 314 virtual void accept( Visitor & v ) override { v.visit( this ); }315 virtual void accept( Visitor & v ) const override { v.visit( this ); }316 virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }317 virtual void print( std::ostream & os, Indenter indent = {} ) const override;318 };319 320 /// VariableExpr represents an expression that simply refers to the value of a named variable.321 /// Does not take ownership of var.322 class VariableExpr : public Expression {323 public:324 DeclarationWithType * var;325 326 VariableExpr();327 VariableExpr( DeclarationWithType * var );328 VariableExpr( const VariableExpr & other );329 virtual ~VariableExpr();330 331 bool get_lvalue() const final;332 333 DeclarationWithType * get_var() const { return var; }334 void set_var( DeclarationWithType * newValue ) { var = newValue; }335 336 static VariableExpr * functionPointer( FunctionDecl * decl );337 338 virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }339 350 virtual void accept( Visitor & v ) override { v.visit( this ); } 340 351 virtual void accept( Visitor & v ) const override { v.visit( this ); } -
src/SynTree/LinkageSpec.cc
rbdfc032 reef8dfb 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 13:22:09 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Dec 16 15:02:29 201913 // Update Count : 2 811 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Mar 2 16:13:00 2020 13 // Update Count : 29 14 14 // 15 15 … … 20 20 21 21 #include "LinkageSpec.h" 22 #include "Common/CodeLocation.h" 22 23 #include "Common/SemanticError.h" 23 24 -
src/SynTree/LinkageSpec.h
rbdfc032 reef8dfb 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 13:24:28 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Dec 16 15:03:43 201913 // Update Count : 2 011 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Mar 2 16:13:00 2020 13 // Update Count : 21 14 14 // 15 15 … … 18 18 #include <string> 19 19 20 #include "Common/CodeLocation.h" 20 struct CodeLocation; 21 21 22 22 namespace LinkageSpec { -
src/SynTree/Mutator.h
rbdfc032 reef8dfb 51 51 virtual Statement * mutate( CatchStmt * catchStmt ) = 0; 52 52 virtual Statement * mutate( FinallyStmt * catchStmt ) = 0; 53 virtual Statement * mutate( SuspendStmt * suspendStmt ) = 0; 53 54 virtual Statement * mutate( WaitForStmt * waitforStmt ) = 0; 54 55 virtual Declaration * mutate( WithStmt * withStmt ) = 0; -
src/SynTree/NamedTypeDecl.cc
rbdfc032 reef8dfb 22 22 #include "LinkageSpec.h" // for Spec, Cforall, linkageName 23 23 #include "Type.h" // for Type, Type::StorageClasses 24 #include "CompilationState.h" 24 25 25 26 NamedTypeDecl::NamedTypeDecl( const std::string &name, Type::StorageClasses scs, Type *base ) … … 28 29 NamedTypeDecl::NamedTypeDecl( const NamedTypeDecl &other ) 29 30 : Parent( other ), base( maybeClone( other.base ) ) { 30 cloneAll( other.parameters, parameters );31 31 cloneAll( other.assertions, assertions ); 32 32 } … … 34 34 NamedTypeDecl::~NamedTypeDecl() { 35 35 delete base; 36 deleteAll( parameters );37 36 deleteAll( assertions ); 38 37 } … … 41 40 using namespace std; 42 41 43 if ( name != "" ) os << name << ": "; 42 if ( ! name.empty() ) { 43 if( deterministic_output && isUnboundType(name) ) os << "[unbound]:"; 44 else os << name << ": "; 45 } 44 46 45 47 if ( linkage != LinkageSpec::Cforall ) { … … 51 53 os << " for "; 52 54 base->print( os, indent+1 ); 53 } // if54 if ( ! parameters.empty() ) {55 os << endl << indent << "... with parameters" << endl;56 printAll( parameters, os, indent+1 );57 55 } // if 58 56 if ( ! assertions.empty() ) { … … 72 70 base->print( os, indent+1 ); 73 71 } // if 74 if ( ! parameters.empty() ) {75 os << endl << indent << "... with parameters" << endl;76 printAll( parameters, os, indent+1 );77 } // if78 72 } 79 73 -
src/SynTree/ReferenceToType.cc
rbdfc032 reef8dfb 24 24 #include "Type.h" // for TypeInstType, StructInstType, UnionInstType 25 25 #include "TypeSubstitution.h" // for TypeSubstitution 26 #include "CompilationState.h" 26 27 27 28 class Attribute; … … 205 206 206 207 Type::print( os, indent ); 207 os << "instance of " << typeString() << " " << get_name() << " (" << ( isFtype ? "" : "not" ) << " function type)"; 208 os << "instance of " << typeString() << " "; 209 const auto & name_ = get_name(); 210 if( deterministic_output && isUnboundType(name) ) os << "[unbound]"; 211 else os << name; 212 os << " (" << ( isFtype ? "" : "not" ) << " function type)"; 208 213 if ( ! parameters.empty() ) { 209 214 os << endl << indent << "... with parameters" << endl; -
src/SynTree/Statement.cc
rbdfc032 reef8dfb 420 420 } 421 421 422 SuspendStmt::SuspendStmt( const SuspendStmt & other ) 423 : Statement( other ) 424 , then( maybeClone(other.then) ) 425 {} 426 427 SuspendStmt::~SuspendStmt() { 428 delete then; 429 } 430 431 void SuspendStmt::print( std::ostream & os, Indenter indent ) const { 432 os << "Suspend Statement"; 433 switch (type) { 434 case None : os << " with implicit target"; break; 435 case Generator: os << " for generator" ; break; 436 case Coroutine: os << " for coroutine" ; break; 437 } 438 os << endl; 439 indent += 1; 440 441 if(then) { 442 os << indent << " with post statement :" << endl; 443 then->print( os, indent + 1); 444 } 445 } 446 422 447 WaitForStmt::WaitForStmt() : Statement() { 423 448 timeout.time = nullptr; -
src/SynTree/Statement.h
rbdfc032 reef8dfb 422 422 }; 423 423 424 class SuspendStmt : public Statement { 425 public: 426 CompoundStmt * then = nullptr; 427 enum Type { None, Coroutine, Generator } type = None; 428 429 SuspendStmt() = default; 430 SuspendStmt( const SuspendStmt & ); 431 virtual ~SuspendStmt(); 432 433 virtual SuspendStmt * clone() const override { return new SuspendStmt( *this ); } 434 virtual void accept( Visitor & v ) override { v.visit( this ); } 435 virtual void accept( Visitor & v ) const override { v.visit( this ); } 436 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 437 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 438 }; 439 424 440 class WaitForStmt : public Statement { 425 441 public: … … 502 518 class ImplicitCtorDtorStmt : public Statement { 503 519 public: 504 // Non-owned pointer to the constructor/destructor statement520 // the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere 505 521 Statement * callStmt; 506 522 -
src/SynTree/SynTree.h
rbdfc032 reef8dfb 54 54 class CatchStmt; 55 55 class FinallyStmt; 56 class SuspendStmt; 56 57 class WaitForStmt; 57 58 class WithStmt; -
src/SynTree/Type.cc
rbdfc032 reef8dfb 156 156 const Type::Qualifiers noQualifiers; 157 157 158 bool isUnboundType(const Type * type) { 159 if (auto typeInst = dynamic_cast<const TypeInstType *>(type)) { 160 // xxx - look for a type name produced by renameTyVars. 161 162 // TODO: once TypeInstType representation is updated, it should properly check 163 // if the context id is filled. this is a temporary hack for now 164 return isUnboundType(typeInst->name); 165 } 166 return false; 167 } 168 169 bool isUnboundType(const std::string & tname) { 170 // xxx - look for a type name produced by renameTyVars. 171 172 // TODO: once TypeInstType representation is updated, it should properly check 173 // if the context id is filled. this is a temporary hack for now 174 if (std::count(tname.begin(), tname.end(), '_') >= 3) { 175 return true; 176 } 177 return false; 178 } 179 158 180 // Local Variables: // 159 181 // tab-width: 4 // -
src/SynTree/Type.h
rbdfc032 reef8dfb 733 733 }; 734 734 735 736 bool isUnboundType(const Type * type); 737 bool isUnboundType(const std::string & tname); 738 735 739 // Local Variables: // 736 740 // tab-width: 4 // -
src/SynTree/TypeDecl.cc
rbdfc032 reef8dfb 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 15:26:14 201913 // Update Count : 2 112 // Last Modified On : Thu Oct 8 18:18:55 2020 13 // Update Count : 22 14 14 // 15 15 … … 21 21 #include "Type.h" // for Type, Type::StorageClasses 22 22 23 TypeDecl::TypeDecl( const std::string & name, Type::StorageClasses scs, Type * type, Kind kind, bool sized, Type * init ) : Parent( name, scs, type ), kind( kind ), sized( kind == Ttype || sized ), init( init ) { 23 TypeDecl::TypeDecl( const std::string & name, Type::StorageClasses scs, Type * type, Kind kind, bool sized, Type * init ) : 24 Parent( name, scs, type ), kind( kind ), sized( kind == Ttype || sized ), init( init ) { 24 25 } 25 26 -
src/SynTree/Visitor.h
rbdfc032 reef8dfb 78 78 virtual void visit( FinallyStmt * node ) { visit( const_cast<const FinallyStmt *>(node) ); } 79 79 virtual void visit( const FinallyStmt * finallyStmt ) = 0; 80 virtual void visit( SuspendStmt * node ) { visit( const_cast<const SuspendStmt *>(node) ); } 81 virtual void visit( const SuspendStmt * suspendStmt ) = 0; 80 82 virtual void visit( WaitForStmt * node ) { visit( const_cast<const WaitForStmt *>(node) ); } 81 83 virtual void visit( const WaitForStmt * waitforStmt ) = 0; -
src/SynTree/module.mk
rbdfc032 reef8dfb 20 20 SynTree/ApplicationExpr.cc \ 21 21 SynTree/ArrayType.cc \ 22 SynTree/Attribute.cc \ 23 SynTree/Attribute.h \ 22 24 SynTree/AttrType.cc \ 23 SynTree/ Attribute.cc\25 SynTree/BaseSyntaxNode.h \ 24 26 SynTree/BasicType.cc \ 25 27 SynTree/CommaExpr.cc \ 26 28 SynTree/CompoundStmt.cc \ 27 29 SynTree/Constant.cc \ 30 SynTree/Constant.h \ 31 SynTree/Declaration.cc \ 32 SynTree/Declaration.h \ 33 SynTree/DeclarationWithType.cc \ 28 34 SynTree/DeclReplacer.cc \ 35 SynTree/DeclReplacer.h \ 29 36 SynTree/DeclStmt.cc \ 30 SynTree/Declaration.cc \31 SynTree/DeclarationWithType.cc \32 37 SynTree/Expression.cc \ 38 SynTree/Expression.h \ 33 39 SynTree/FunctionDecl.cc \ 34 40 SynTree/FunctionType.cc \ 35 41 SynTree/Initializer.cc \ 42 SynTree/Initializer.h \ 43 SynTree/Label.h \ 36 44 SynTree/LinkageSpec.cc \ 45 SynTree/LinkageSpec.h \ 46 SynTree/Mutator.h \ 37 47 SynTree/NamedTypeDecl.cc \ 38 48 SynTree/ObjectDecl.cc \ … … 41 51 SynTree/ReferenceType.cc \ 42 52 SynTree/Statement.cc \ 53 SynTree/Statement.h \ 54 SynTree/SynTree.h \ 43 55 SynTree/TupleExpr.cc \ 44 56 SynTree/TupleType.cc \ … … 46 58 SynTree/TypeDecl.cc \ 47 59 SynTree/TypeExpr.cc \ 60 SynTree/Type.h \ 61 SynTree/TypeofType.cc \ 48 62 SynTree/TypeSubstitution.cc \ 49 SynTree/Type ofType.cc\63 SynTree/TypeSubstitution.h \ 50 64 SynTree/VarArgsType.cc \ 65 SynTree/Visitor.h \ 51 66 SynTree/VoidType.cc \ 52 67 SynTree/ZeroOneType.cc -
src/Tuples/Explode.cc
rbdfc032 reef8dfb 129 129 for ( const ast::Expr * expr : tupleExpr->exprs ) { 130 130 exprs.emplace_back( applyCast( expr, false ) ); 131 //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );132 131 } 133 132 if ( first ) { … … 148 147 } 149 148 150 const ast::Expr * post mutate( const ast::UniqueExpr * node ) {149 const ast::Expr * postvisit( const ast::UniqueExpr * node ) { 151 150 // move cast into unique expr so that the unique expr has type T& rather than 152 151 // type T. In particular, this transformation helps with generating the … … 162 161 castAdded = false; 163 162 const ast::Type * newType = getReferenceBase( newNode->result ); 164 return new ast::CastExpr{ newNode->location, n ode, newType };163 return new ast::CastExpr{ newNode->location, newNode, newType }; 165 164 } 166 165 return newNode; 167 166 } 168 167 169 const ast::Expr * post mutate( const ast::TupleIndexExpr * tupleExpr ) {168 const ast::Expr * postvisit( const ast::TupleIndexExpr * tupleExpr ) { 170 169 // tuple index expr needs to be rebuilt to ensure that the type of the 171 170 // field is consistent with the type of the tuple expr, since the field … … 180 179 ast::Pass<CastExploderCore> exploder; 181 180 expr = expr->accept( exploder ); 182 if ( ! exploder. pass.foundUniqueExpr ) {181 if ( ! exploder.core.foundUniqueExpr ) { 183 182 expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } }; 184 183 } -
src/Tuples/Explode.h
rbdfc032 reef8dfb 210 210 } 211 211 // Cast a reference away to a value-type to allow further explosion. 212 if ( dynamic_cast< const ast::ReferenceType *>( local->result.get()) ) {212 if ( local->result.as< ast::ReferenceType >() ) { 213 213 local = new ast::CastExpr{ local, tupleType }; 214 214 } … … 220 220 // delete idx; 221 221 } 222 // delete local;223 222 } 224 223 } else { -
src/Tuples/TupleAssignment.cc
rbdfc032 reef8dfb 465 465 // resolve ctor/dtor for the new object 466 466 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 467 InitTweak::genCtorInit( location, ret ), spotter.crntFinder. symtab);467 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms ); 468 468 // remove environments from subexpressions of stmtExpr 469 469 ast::Pass< EnvRemover > rm{ env }; … … 560 560 // resolve the cast expression so that rhsCand return type is bound by the cast 561 561 // type as needed, and transfer the resulting environment 562 ResolvExpr::CandidateFinder finder{ spotter.crntFinder. symtab, env };562 ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env }; 563 563 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 564 564 assert( finder.candidates.size() == 1 ); … … 609 609 // explode the LHS so that each field of a tuple-valued expr is assigned 610 610 ResolvExpr::CandidateList lhs; 611 explode( *lhsCand, crntFinder. symtab, back_inserter(lhs), true );611 explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true ); 612 612 for ( ResolvExpr::CandidateRef & cand : lhs ) { 613 613 // each LHS value must be a reference - some come in with a cast, if not … … 629 629 if ( isTuple( rhsCand->expr ) ) { 630 630 // multiple assignment 631 explode( *rhsCand, crntFinder. symtab, back_inserter(rhs), true );631 explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true ); 632 632 matcher.reset( 633 633 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); … … 648 648 // multiple assignment 649 649 ResolvExpr::CandidateList rhs; 650 explode( rhsCand, crntFinder. symtab, back_inserter(rhs), true );650 explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true ); 651 651 matcher.reset( 652 652 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); … … 678 678 ) 679 679 680 ResolvExpr::CandidateFinder finder{ crntFinder. symtab, matcher->env };680 ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env }; 681 681 682 682 try { -
src/Tuples/TupleExpansion.cc
rbdfc032 reef8dfb 323 323 std::vector<ast::ptr<ast::Type>> types; 324 324 ast::CV::Qualifiers quals{ 325 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |325 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | 326 326 ast::CV::Atomic | ast::CV::Mutex }; 327 327 -
src/Tuples/Tuples.cc
rbdfc032 reef8dfb 43 43 }; 44 44 struct ImpurityDetectorIgnoreUnique : public ImpurityDetector { 45 using ImpurityDetector::previsit; 45 46 void previsit( ast::UniqueExpr const * ) { 46 47 visit_children = false; … … 52 53 ast::Pass<Detector> detector; 53 54 expr->accept( detector ); 54 return detector. pass.maybeImpure;55 return detector.core.maybeImpure; 55 56 } 56 57 } // namespace -
src/Tuples/module.mk
rbdfc032 reef8dfb 15 15 ############################################################################### 16 16 17 SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \ 18 Tuples/Tuples.cc 19 SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \ 20 Tuples/Tuples.cc 17 SRC_TUPLES = \ 18 Tuples/Explode.cc \ 19 Tuples/Explode.h \ 20 Tuples/TupleAssignment.cc \ 21 Tuples/TupleExpansion.cc \ 22 Tuples/Tuples.cc \ 23 Tuples/Tuples.h 24 25 26 SRC += $(SRC_TUPLES) 27 SRCDEMANGLE += $(SRC_TUPLES) -
src/Validate/module.mk
rbdfc032 reef8dfb 15 15 ############################################################################### 16 16 17 SRC += Validate/HandleAttributes.cc Validate/ FindSpecialDecls.cc18 SRCDEMANGLE += Validate/HandleAttributes.cc Validate/ FindSpecialDecls.cc17 SRC += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h 18 SRCDEMANGLE += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h -
src/Virtual/ExpandCasts.cc
rbdfc032 reef8dfb 10 10 // Created On : Mon Jul 24 13:59:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tus Aug 2 14:59:00 201713 // Update Count : 112 // Last Modified On : Fri Jul 31 10:29:00 2020 13 // Update Count : 4 14 14 // 15 15 … … 18 18 #include <cassert> // for assert, assertf 19 19 #include <iterator> // for back_inserter, inserter 20 #include <map> // for map, _Rb_tree_iterator, map<>::ite...21 20 #include <string> // for string, allocator, operator==, ope... 22 #include <utility> // for pair23 21 24 22 #include "Common/PassVisitor.h" // for PassVisitor 23 #include "Common/ScopedMap.h" // for ScopedMap 25 24 #include "Common/SemanticError.h" // for SemanticError 25 #include "SymTab/Mangler.h" // for mangleType 26 26 #include "SynTree/Declaration.h" // for ObjectDecl, StructDecl, FunctionDecl 27 27 #include "SynTree/Expression.h" // for VirtualCastExpr, CastExpr, Address... … … 31 31 32 32 namespace Virtual { 33 34 // Indented until the new ast code gets added. 35 36 /// Maps virtual table types the instance for that type. 37 class VirtualTableMap final { 38 ScopedMap<std::string, ObjectDecl *> vtable_instances; 39 public: 40 void enterScope() { 41 vtable_instances.beginScope(); 42 } 43 void leaveScope() { 44 vtable_instances.endScope(); 45 } 46 47 ObjectDecl * insert( ObjectDecl * vtableDecl ) { 48 std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type ); 49 ObjectDecl *& value = vtable_instances[ mangledName ]; 50 if ( value ) { 51 if ( vtableDecl->storageClasses.is_extern ) { 52 return nullptr; 53 } else if ( ! value->storageClasses.is_extern ) { 54 return value; 55 } 56 } 57 value = vtableDecl; 58 return nullptr; 59 } 60 61 ObjectDecl * lookup( const Type * vtableType ) { 62 std::string const & mangledName = SymTab::Mangler::mangleType( vtableType ); 63 const auto it = vtable_instances.find( mangledName ); 64 return ( vtable_instances.end() == it ) ? nullptr : it->second; 65 } 66 }; 33 67 34 68 /* Currently virtual depends on the rather brittle name matching between … … 39 73 */ 40 74 75 namespace { 76 41 77 std::string get_vtable_name( std::string const & name ) { 42 78 return name + "_vtable"; … … 53 89 std::string get_vtable_inst_name_root( std::string const & name ) { 54 90 return get_vtable_name_root( name.substr(1, name.size() - 10 ) ); 55 }56 57 bool is_vtable_name( std::string const & name ) {58 return (name.substr( name.size() - 7 ) == "_vtable" );59 91 } 60 92 … … 64 96 } 65 97 98 } // namespace 99 66 100 class VirtualCastCore { 67 std::map<std::string, ObjectDecl *> vtable_instances;68 FunctionDecl *vcast_decl;69 StructDecl *pvt_decl;70 71 101 Type * pointer_to_pvt(int level_of_indirection) { 72 102 Type * type = new StructInstType( … … 80 110 public: 81 111 VirtualCastCore() : 82 vtable_instances(), vcast_decl( nullptr ), pvt_decl( nullptr )112 indexer(), vcast_decl( nullptr ), pvt_decl( nullptr ) 83 113 {} 84 114 … … 88 118 89 119 Expression * postmutate( VirtualCastExpr * castExpr ); 120 121 VirtualTableMap indexer; 122 private: 123 FunctionDecl *vcast_decl; 124 StructDecl *pvt_decl; 90 125 }; 91 126 … … 107 142 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) { 108 143 if ( is_vtable_inst_name( objectDecl->get_name() ) ) { 109 vtable_instances[objectDecl->get_name()] = objectDecl; 110 } 111 } 144 if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) { 145 std::string msg = "Repeated instance of virtual table, original found at: "; 146 msg += existing->location.filename; 147 msg += ":" + toString( existing->location.first_line ); 148 SemanticError( objectDecl->location, msg ); 149 } 150 } 151 } 152 153 namespace { 154 155 /// Better error locations for generated casts. 156 CodeLocation castLocation( const VirtualCastExpr * castExpr ) { 157 if ( castExpr->location.isSet() ) { 158 return castExpr->location; 159 } else if ( castExpr->arg->location.isSet() ) { 160 return castExpr->arg->location; 161 } else if ( castExpr->result->location.isSet() ) { 162 return castExpr->result->location; 163 } else { 164 return CodeLocation(); 165 } 166 } 167 168 [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) { 169 SemanticError( castLocation( castExpr ), message ); 170 } 171 172 /// Get the virtual table type used in a virtual cast. 173 Type * getVirtualTableType( const VirtualCastExpr * castExpr ) { 174 const Type * objectType; 175 if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) { 176 objectType = target->base; 177 } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) { 178 objectType = target->base; 179 } else { 180 castError( castExpr, "Virtual cast type must be a pointer or reference type." ); 181 } 182 assert( objectType ); 183 184 const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType ); 185 if ( nullptr == structType ) { 186 castError( castExpr, "Virtual cast type must refer to a structure type." ); 187 } 188 const StructDecl * structDecl = structType->baseStruct; 189 assert( structDecl ); 190 191 const ObjectDecl * fieldDecl = nullptr; 192 if ( 0 < structDecl->members.size() ) { 193 const Declaration * memberDecl = structDecl->members.front(); 194 assert( memberDecl ); 195 fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 196 if ( fieldDecl && fieldDecl->name != "virtual_table" ) { 197 fieldDecl = nullptr; 198 } 199 } 200 if ( nullptr == fieldDecl ) { 201 castError( castExpr, "Virtual cast type must have a leading virtual_table field." ); 202 } 203 const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type ); 204 if ( nullptr == fieldType ) { 205 castError( castExpr, "Virtual cast type virtual_table field is not a pointer." ); 206 } 207 assert( fieldType->base ); 208 auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base ); 209 assert( virtualStructType ); 210 211 // Here is the type, but if it is polymorphic it will have lost information. 212 // (Always a clone so that it may always be deleted.) 213 StructInstType * virtualType = virtualStructType->clone(); 214 if ( ! structType->parameters.empty() ) { 215 deleteAll( virtualType->parameters ); 216 virtualType->parameters.clear(); 217 cloneAll( structType->parameters, virtualType->parameters ); 218 } 219 return virtualType; 220 } 221 222 } // namespace 112 223 113 224 Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) { 114 assertf( castExpr-> get_result(), "Virtual Cast target not found before expansion." );225 assertf( castExpr->result, "Virtual Cast target not found before expansion." ); 115 226 116 227 assert( vcast_decl ); 117 228 assert( pvt_decl ); 118 229 119 // May only cast to a pointer or reference type. 120 // A earlier validation should give a syntax error, this is 121 // just to make sure errors don't creep during translation. 122 // Move to helper with more detailed error messages. 123 PointerType * target_type = 124 dynamic_cast<PointerType *>( castExpr->get_result() ); 125 assert( target_type ); 126 127 StructInstType * target_struct = 128 dynamic_cast<StructInstType *>( target_type->get_base() ); 129 assert( target_struct ); 130 131 StructDecl * target_decl = target_struct->get_baseStruct(); 132 133 std::map<std::string, ObjectDecl *>::iterator found = 134 vtable_instances.find( 135 get_vtable_inst_name( target_decl->get_name() ) ); 136 if ( vtable_instances.end() == found ) { 137 assertf( false, "virtual table instance not found." ); 138 } 139 ObjectDecl * table = found->second; 230 const Type * vtable_type = getVirtualTableType( castExpr ); 231 ObjectDecl * table = indexer.lookup( vtable_type ); 232 if ( nullptr == table ) { 233 SemanticError( castLocation( castExpr ), 234 "Could not find virtual table instance." ); 235 } 140 236 141 237 Expression * result = new CastExpr( 142 //new ApplicationExpr(143 //new AddressExpr( new VariableExpr( vcast_decl ) ),144 //new CastExpr( new VariableExpr( vcast_decl ),145 // new PointerType( noQualifiers,146 // vcast_decl->get_type()->clone()147 // )148 // ),149 238 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), { 150 239 new CastExpr( … … 163 252 castExpr->set_result( nullptr ); 164 253 delete castExpr; 254 delete vtable_type; 165 255 return result; 166 256 } -
src/Virtual/module.mk
rbdfc032 reef8dfb 15 15 ############################################################################### 16 16 17 SRC += Virtual/ExpandCasts.cc 17 SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \ 18 Virtual/Tables.cc Virtual/Tables.h 19 20 SRCDEMANGLE += Virtual/Tables.cc -
src/config.h.in
rbdfc032 reef8dfb 27 27 /* Location of cfa install. */ 28 28 #undef CFA_PREFIX 29 30 /* Sets whether or not to use the new-ast, this is adefault value and can be 31 overrided by --old-ast and --new-ast */ 32 #undef CFA_USE_NEW_AST 29 33 30 34 /* Major.Minor */ -
src/main.cc
rbdfc032 reef8dfb 9 9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Dec 16 17:55:53 201913 // Update Count : 6 2711 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Dec 7 15:29:00 2020 13 // Update Count : 639 14 14 // 15 15 … … 31 31 using namespace std; 32 32 33 33 #include "AST/Convert.hpp" 34 34 #include "CompilationState.h" 35 35 #include "../config.h" // for CFA_LIBDIR … … 40 40 #include "CodeTools/ResolvProtoDump.h" // for dumpAsResolvProto 41 41 #include "CodeTools/TrackLoc.h" // for fillLocations 42 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 42 43 #include "Common/CompilerError.h" // for CompilerError 43 44 #include "Common/Stats.h" … … 105 106 106 107 static void backtrace( int start ) { // skip first N stack frames 107 enum { Frames = 50 };108 enum { Frames = 50, }; // maximum number of stack frames 108 109 void * array[Frames]; 109 int size = ::backtrace( array, Frames );110 size_t size = ::backtrace( array, Frames ); 110 111 char ** messages = ::backtrace_symbols( array, size ); // does not demangle names 111 112 … … 114 115 115 116 // skip last 2 stack frames after main 116 for ( int i = start; i < size - 2 && messages != nullptr; i += 1 ) {117 for ( unsigned int i = start; i < size - 2 && messages != nullptr; i += 1 ) { 117 118 char * mangled_name = nullptr, * offset_begin = nullptr, * offset_end = nullptr; 118 119 … … 180 181 } // sigSegvBusHandler 181 182 183 static void sigFpeHandler( SIGPARMS ) { 184 const char * msg; 185 186 switch ( sfp->si_code ) { 187 case FPE_INTDIV: case FPE_FLTDIV: msg = "divide by zero"; break; 188 case FPE_FLTOVF: msg = "overflow"; break; 189 case FPE_FLTUND: msg = "underflow"; break; 190 case FPE_FLTRES: msg = "inexact result"; break; 191 case FPE_FLTINV: msg = "invalid operation"; break; 192 default: msg = "unknown"; 193 } // choose 194 cerr << "Computation error " << msg << " at location " << sfp->si_addr << endl 195 << "Possible cause is constant-expression evaluation invalid." << endl; 196 backtrace( 2 ); // skip first 2 stack frames 197 abort(); // cause core dump for debugging 198 } // sigFpeHandler 199 182 200 static void sigAbortHandler( SIGPARMS ) { 183 201 backtrace( 6 ); // skip first 6 stack frames … … 193 211 Signal( SIGSEGV, sigSegvBusHandler, SA_SIGINFO ); 194 212 Signal( SIGBUS, sigSegvBusHandler, SA_SIGINFO ); 213 Signal( SIGFPE, sigFpeHandler, SA_SIGINFO ); 195 214 Signal( SIGABRT, sigAbortHandler, SA_SIGINFO ); 196 215 … … 294 313 } // if 295 314 315 PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) ); 296 316 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) ); 297 317 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) ); … … 321 341 } // if 322 342 323 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 324 if ( exprp ) { 325 dump( translationUnit ); 326 return EXIT_SUCCESS; 327 } // if 343 if( useNewAST ) { 344 if (Stats::Counters::enabled) { 345 ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New"); 346 ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New"); 347 } 348 auto transUnit = convert( move( translationUnit ) ); 349 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 350 if ( exprp ) { 351 translationUnit = convert( move( transUnit ) ); 352 dump( translationUnit ); 353 return EXIT_SUCCESS; 354 } // if 355 356 forceFillCodeLocations( transUnit ); 357 358 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary())); 359 translationUnit = convert( move( transUnit ) ); 360 } else { 361 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 362 if ( exprp ) { 363 dump( translationUnit ); 364 return EXIT_SUCCESS; 365 } 366 367 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) ); 368 } 328 369 329 370 // fix ObjectDecl - replaces ConstructorInit nodes 330 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );331 371 if ( ctorinitp ) { 332 372 dump ( translationUnit ); … … 336 376 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused 337 377 338 PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) );378 PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) ); 339 379 340 380 PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) ); … … 425 465 426 466 427 static const char optstring[] = ":c:ghlLmNnp P:S:twW:D:";467 static const char optstring[] = ":c:ghlLmNnpdOAP:S:twW:D:"; 428 468 429 469 enum { PreludeDir = 128 }; … … 438 478 { "no-prelude", no_argument, nullptr, 'n' }, 439 479 { "prototypes", no_argument, nullptr, 'p' }, 480 { "deterministic-out", no_argument, nullptr, 'd' }, 481 { "old-ast", no_argument, nullptr, 'O'}, 482 { "new-ast", no_argument, nullptr, 'A'}, 440 483 { "print", required_argument, nullptr, 'P' }, 441 484 { "prelude-dir", required_argument, nullptr, PreludeDir }, … … 449 492 450 493 static const char * description[] = { 451 "diagnostic color: never, always, or auto.", 452 "wait for gdb to attach", 453 "print help message", 454 "generate libcfa.c", 455 "generate line marks", 456 "do not replace main", 457 "do not generate line marks", 458 "do not read prelude", 494 "diagnostic color: never, always, or auto.", // -c 495 "wait for gdb to attach", // -g 496 "print help message", // -h 497 "generate libcfa.c", // -l 498 "generate line marks", // -L 499 "do not replace main", // -m 500 "do not generate line marks", // -N 501 "do not read prelude", // -n 459 502 "generate prototypes for prelude functions", // -p 460 "print", // -P 503 "only print deterministic output", // -d 504 "Use the old-ast", // -O 505 "Use the new-ast", // -A 506 "print", // -P 461 507 "<directory> prelude directory for debug/nodebug", // no flag 462 508 "<option-list> enable profiling information:\n counters,heap,time,all,none", // -S 463 "building cfa standard lib", 464 "", 465 "", 466 "", 509 "building cfa standard lib", // -t 510 "", // -w 511 "", // -W 512 "", // -D 467 513 }; // description 468 514 … … 562 608 genproto = true; 563 609 break; 610 case 'd': // don't print non-deterministic output 611 deterministic_output = true; 612 break; 613 case 'O': // don't print non-deterministic output 614 useNewAST = false; 615 break; 616 case 'A': // don't print non-deterministic output 617 useNewAST = true; 618 break; 564 619 case 'P': // print options 565 620 for ( int i = 0;; i += 1 ) {
Note:
See TracChangeset
for help on using the changeset viewer.