- 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, stuck-waitfor-destruct
- 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/AST
- Files:
-
- 3 added
- 31 edited
-
Attribute.hpp (modified) (1 diff)
-
CVQualifiers.hpp (modified) (2 diffs)
-
Convert.cpp (modified) (42 diffs)
-
Convert.hpp (modified) (1 diff)
-
Copy.hpp (added)
-
Decl.cpp (modified) (1 diff)
-
Decl.hpp (modified) (8 diffs)
-
DeclReplacer.cpp (modified) (3 diffs)
-
DeclReplacer.hpp (modified) (1 diff)
-
Eval.hpp (added)
-
Expr.cpp (modified) (13 diffs)
-
Expr.hpp (modified) (23 diffs)
-
Fwd.hpp (modified) (4 diffs)
-
GenericSubstitution.cpp (modified) (2 diffs)
-
Init.hpp (modified) (5 diffs)
-
Node.cpp (modified) (4 diffs)
-
Node.hpp (modified) (12 diffs)
-
Pass.hpp (modified) (11 diffs)
-
Pass.impl.hpp (modified) (124 diffs)
-
Pass.proto.hpp (modified) (13 diffs)
-
Print.cpp (modified) (11 diffs)
-
Stmt.hpp (modified) (3 diffs)
-
SymbolTable.cpp (modified) (12 diffs)
-
SymbolTable.hpp (modified) (5 diffs)
-
TranslationUnit.hpp (added)
-
Type.cpp (modified) (7 diffs)
-
Type.hpp (modified) (13 diffs)
-
TypeEnvironment.cpp (modified) (20 diffs)
-
TypeEnvironment.hpp (modified) (9 diffs)
-
TypeSubstitution.cpp (modified) (9 diffs)
-
TypeSubstitution.hpp (modified) (9 diffs)
-
Visitor.hpp (modified) (1 diff)
-
module.mk (modified) (1 diff)
-
porting.md (modified) (6 diffs)
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`
Note:
See TracChangeset
for help on using the changeset viewer.