Changes in / [dab09ad:fb0ae06]
- Files:
-
- 6 added
- 68 edited
Legend:
- Unmodified
- Added
- Removed
-
configure.ac
rdab09ad rfb0ae06 24 24 #Trasforming cc1 will break compilation 25 25 M4CFA_PROGRAM_NAME 26 27 #============================================================================== 28 # New AST toggling support 29 AH_TEMPLATE([CFA_USE_NEW_AST],[Sets whether or not to use the new-ast, this is adefault value and can be overrided by --old-ast and --new-ast]) 30 AC_ARG_ENABLE(new-ast, 31 [ --enable-new-ast whether or not to use new ast as the default AST algorithm], 32 [case "${enableval}" in 33 yes) newast=true ;; 34 no) newast=false ;; 35 *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;; 36 esac],[newast=false]) 37 AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast) 26 38 27 39 #============================================================================== -
libcfa/src/Makefile.am
rdab09ad rfb0ae06 44 44 45 45 headers = common.hfa fstream.hfa heap.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa \ 46 time.hfa stdlib.hfa memory.hfaparseargs.hfa \46 time.hfa stdlib.hfa parseargs.hfa \ 47 47 containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa 48 48 -
libcfa/src/concurrency/ready_queue.cfa
rdab09ad rfb0ae06 419 419 // Actually pop the list 420 420 struct $thread * thrd; 421 bool emptied; 422 [thrd, emptied] = pop(lane); 421 thrd = pop(lane); 423 422 424 423 /* paranoid */ verify(thrd); … … 457 456 if(head(lane)->link.next == thrd) { 458 457 $thread * pthrd; 459 bool emptied; 460 [pthrd, emptied] = pop(lane); 458 pthrd = pop(lane); 461 459 462 460 /* paranoid */ verify( pthrd == thrd ); … … 608 606 while(!is_empty(lanes.data[idx])) { 609 607 struct $thread * thrd; 610 __attribute__((unused)) bool _; 611 [thrd, _] = pop(lanes.data[idx]); 608 thrd = pop(lanes.data[idx]); 612 609 613 610 push(cltr, thrd); -
libcfa/src/concurrency/ready_subqueue.hfa
rdab09ad rfb0ae06 144 144 // returns popped 145 145 // returns true of lane was empty before push, false otherwise 146 [$thread *, bool]pop(__intrusive_lane_t & this) {146 $thread * pop(__intrusive_lane_t & this) { 147 147 /* paranoid */ verify(this.lock); 148 148 /* paranoid */ verify(this.before.link.ts != 0ul); … … 162 162 head->link.next = next; 163 163 next->link.prev = head; 164 node->link.[next, prev] = 0p; 164 node->link.next = 0p; 165 node->link.prev = 0p; 165 166 166 167 // Update head time stamp … … 180 181 /* paranoid */ verify(tail(this)->link.prev == head(this)); 181 182 /* paranoid */ verify(head(this)->link.next == tail(this)); 182 return [node, true];183 return node; 183 184 } 184 185 else { … … 187 188 /* paranoid */ verify(head(this)->link.next != tail(this)); 188 189 /* paranoid */ verify(this.before.link.ts != 0); 189 return [node, false];190 return node; 190 191 } 191 192 } -
src/AST/Attribute.hpp
rdab09ad rfb0ae06 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
rdab09ad rfb0ae06 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
rdab09ad rfb0ae06 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" … … 587 588 assert( tgtResnSlots.empty() ); 588 589 589 if ( srcInferred. mode == ast::Expr::InferUnion::Params ) {590 if ( srcInferred.data.inferParams ) { 590 591 const ast::InferredParams &srcParams = srcInferred.inferParams(); 591 592 for (auto & srcParam : srcParams) { … … 593 594 srcParam.second.decl, 594 595 get<Declaration>().accept1(srcParam.second.declptr), 595 get<Type>().accept1(srcParam.second.actualType) ,596 get<Type>().accept1(srcParam.second.formalType) ,597 get<Expression>().accept1(srcParam.second.expr) 596 get<Type>().accept1(srcParam.second.actualType)->clone(), 597 get<Type>().accept1(srcParam.second.formalType)->clone(), 598 get<Expression>().accept1(srcParam.second.expr)->clone() 598 599 )); 599 600 assert(res.second); 600 601 } 601 } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots ) { 602 } 603 if ( srcInferred.data.resnSlots ) { 602 604 const ast::ResnSlots &srcSlots = srcInferred.resnSlots(); 603 605 for (auto srcSlot : srcSlots) { … … 620 622 621 623 tgt->result = get<Type>().accept1(src->result); 624 // Unconditionally use a clone of the result type. 625 // We know this will leak some objects: much of the immediate conversion result. 626 // In some cases, using the conversion result directly gives unintended object sharing. 627 // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache. 628 // But tgt->result must be fully owned privately by tgt. 629 // Applying these conservative copies here means 630 // - weak references point at the declaration's copy, not these expr.result copies (good) 631 // - we copy more objects than really needed (bad, tolerated) 632 if (tgt->result) { 633 tgt->result = tgt->result->clone(); 634 } 622 635 return visitBaseExpr_skipResultType(src, tgt); 623 636 } … … 979 992 980 993 const ast::Expr * visit( const ast::StmtExpr * node ) override final { 994 auto stmts = node->stmts; 995 // disable sharing between multiple StmtExprs explicitly. 996 if (inCache(stmts)) { 997 stmts = ast::deepCopy(stmts.get()); 998 } 981 999 auto rslt = new StmtExpr( 982 get<CompoundStmt>().accept1( node->stmts)1000 get<CompoundStmt>().accept1(stmts) 983 1001 ); 984 1002 … … 1986 2004 1987 2005 assert( oldInferParams.empty() || oldResnSlots.empty() ); 1988 assert( newInferred.mode == ast::Expr::InferUnion::Empty );2006 // assert( newInferred.mode == ast::Expr::InferUnion::Empty ); 1989 2007 1990 2008 if ( !oldInferParams.empty() ) { … … 2117 2135 old->location, 2118 2136 GET_ACCEPT_1(member, DeclWithType), 2119 GET_ACCEPT_1(aggregate, Expr) 2137 GET_ACCEPT_1(aggregate, Expr), 2138 ast::MemberExpr::NoOpConstructionChosen 2120 2139 ) 2121 2140 ); -
src/AST/Decl.cpp
rdab09ad rfb0ae06 50 50 51 51 const Type * FunctionDecl::get_type() const { return type.get(); } 52 void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); } 52 void FunctionDecl::set_type( const Type * t ) { 53 type = strict_dynamic_cast< const FunctionType * >( t ); 54 } 53 55 54 56 // --- TypeDecl -
src/AST/Decl.hpp
rdab09ad rfb0ae06 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 { … … 88 90 virtual const Type * get_type() const = 0; 89 91 /// Set type of this declaration. May be verified by subclass 90 virtual void set_type( Type *) = 0;92 virtual void set_type( const Type * ) = 0; 91 93 92 94 const DeclWithType * accept( Visitor & v ) const override = 0; … … 111 113 112 114 const Type* get_type() const override { return type; } 113 void set_type( Type * ty ) override { type = ty; }115 void set_type( const Type * ty ) override { type = ty; } 114 116 115 117 const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); } … … 133 135 134 136 const Type * get_type() const override; 135 void set_type( Type * t) override;137 void set_type( const Type * t ) override; 136 138 137 139 bool has_body() const { return stmts; } … … 150 152 std::vector<ptr<DeclWithType>> assertions; 151 153 152 NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 153 Type* b, Linkage::Spec spec = Linkage::Cforall ) 154 NamedTypeDecl( 155 const CodeLocation & loc, const std::string & name, Storage::Classes storage, 156 const Type * b, Linkage::Spec spec = Linkage::Cforall ) 154 157 : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {} 155 158 … … 186 189 }; 187 190 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 ) {} 191 TypeDecl( 192 const CodeLocation & loc, const std::string & name, Storage::Classes storage, 193 const Type * b, TypeDecl::Kind k, bool s, const Type * i = nullptr ) 194 : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeDecl::Ttype || s ), 195 init( i ) {} 192 196 193 197 const char * typeString() const override; -
src/AST/Expr.cpp
rdab09ad rfb0ae06 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 … … 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 } 70 86 return ret; 87 } 88 89 bool UntypedExpr::get_lvalue() const { 90 std::string fname = InitTweak::getFunctionName( this ); 91 return lvalueFunctionNames.count( fname ); 71 92 } 72 93 … … 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, … … 108 127 AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) { 109 128 if ( arg->result ) { 110 if ( arg-> result->is_lvalue() ) {129 if ( arg->get_lvalue() ) { 111 130 // lvalue, retains all levels of reference, and gains a pointer inside the references 112 131 Type * res = addrType( arg->result ); 113 res->set_lvalue( false ); // result of & is never an lvalue114 132 result = res; 115 133 } else { … … 118 136 dynamic_cast< const ReferenceType * >( arg->result.get() ) ) { 119 137 Type * res = addrType( refType->base ); 120 res->set_lvalue( false ); // result of & is never an lvalue121 138 result = res; 122 139 } else { … … 139 156 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {} 140 157 158 bool CastExpr::get_lvalue() const { 159 // This is actually wrong by C, but it works with our current set-up. 160 return arg->get_lvalue(); 161 } 162 141 163 // --- KeywordCastExpr 142 164 143 165 const char * KeywordCastExpr::targetString() const { 144 166 return AggregateDecl::aggrString( target ); 167 } 168 169 // --- UntypedMemberExpr 170 171 bool UntypedMemberExpr::get_lvalue() const { 172 return aggregate->get_lvalue(); 145 173 } 146 174 … … 153 181 assert( aggregate->result ); 154 182 155 // take ownership of member type 156 result = mem->get_type(); 183 // Deep copy on result type avoids mutation on transitively multiply referenced object. 184 // 185 // Example, adapted from parts of builtins and bootloader: 186 // 187 // forall(dtype T) 188 // struct __Destructor { 189 // T * object; 190 // void (*dtor)(T *); 191 // }; 192 // 193 // forall(dtype S) 194 // void foo(__Destructor(S) &d) { 195 // if (d.dtor) { // here 196 // } 197 // } 198 // 199 // Let e be the "d.dtor" guard espression, which is MemberExpr after resolve. Let d be the 200 // declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level 201 // declaration of __Destructor. Consider the types e.result and d.type. In the old AST, one 202 // is a clone of the other. Ordinary new-AST use would set them up as a multiply-referenced 203 // object. 204 // 205 // e.result: PointerType 206 // .base: FunctionType 207 // .params.front(): ObjectDecl, the anonymous parameter of type T* 208 // .type: PointerType 209 // .base: TypeInstType 210 // let x = that 211 // let y = similar, except start from d.type 212 // 213 // Consider two code lines down, genericSubstitution(...).apply(result). 214 // 215 // Applying this chosen-candidate's type substitution means modifying x, substituting 216 // S for T. This mutation should affect x and not y. 217 218 result = deepCopy(mem->get_type()); 219 157 220 // substitute aggregate generic parameters into member type 158 221 genericSubstitution( aggregate->result ).apply( result ); 159 // ensure lvalue and appropriate restrictions from aggregate type 160 add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue ); 222 // ensure appropriate restrictions from aggregate type 223 add_qualifiers( result, aggregate->result->qualifiers ); 224 } 225 226 MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg, 227 MemberExpr::NoOpConstruction overloadSelector ) 228 : Expr( loc ), member( mem ), aggregate( agg ) { 229 assert( member ); 230 assert( aggregate ); 231 assert( aggregate->result ); 232 (void) overloadSelector; 233 } 234 235 bool MemberExpr::get_lvalue() const { 236 // This is actually wrong by C, but it works with our current set-up. 237 return true; 161 238 } 162 239 … … 170 247 assert( var ); 171 248 assert( var->get_type() ); 172 result = var->get_type(); 173 add_qualifiers( result, CV::Lvalue ); 249 result = shallowCopy( var->get_type() ); 250 } 251 252 bool VariableExpr::get_lvalue() const { 253 // It isn't always an lvalue, but it is never an rvalue. 254 return true; 174 255 } 175 256 … … 258 339 : Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {} 259 340 341 // --- CommaExpr 342 bool CommaExpr::get_lvalue() const { 343 // This is wrong by C, but the current implementation uses it. 344 // (ex: Specialize, Lvalue and Box) 345 return arg2->get_lvalue(); 346 } 347 260 348 // --- ConstructorExpr 261 349 … … 276 364 assert( t && i ); 277 365 result = t; 278 add_qualifiers( result, CV::Lvalue ); 366 } 367 368 bool CompoundLiteralExpr::get_lvalue() const { 369 return true; 279 370 } 280 371 … … 293 384 // like MemberExpr, TupleIndexExpr is always an lvalue 294 385 result = type->types[ index ]; 295 add_qualifiers( result, CV::Lvalue ); 386 } 387 388 bool TupleIndexExpr::get_lvalue() const { 389 return tuple->get_lvalue(); 296 390 } 297 391 -
src/AST/Expr.hpp
rdab09ad rfb0ae06 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; } 110 114 111 115 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(); 116 if (!data.resnSlots) { 117 data.resnSlots = new ResnSlots(); 116 118 } 117 assertf(false, "unreachable");119 return *data.resnSlots; 118 120 } 119 121 120 122 const ResnSlots& resnSlots() const { 121 if ( mode ==Slots) {122 return data.resnSlots;123 if (data.resnSlots) { 124 return *data.resnSlots; 123 125 } 124 126 assertf(false, "Mode was not already resnSlots"); … … 127 129 128 130 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; 131 if (!data.inferParams) { 132 data.inferParams = new InferredParams(); 133 133 } 134 assertf(false, "unreachable");134 return *data.inferParams; 135 135 } 136 136 137 137 const InferredParams& inferParams() const { 138 if ( mode ==Params) {139 return data.inferParams;138 if (data.inferParams) { 139 return *data.inferParams; 140 140 } 141 141 assertf(false, "Mode was not already Params"); … … 143 143 } 144 144 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 } 145 void set_inferParams( InferredParams * ps ) { 146 delete data.resnSlots; 147 data.resnSlots = nullptr; 148 delete data.inferParams; 149 data.inferParams = ps; 158 150 } 159 151 … … 161 153 /// and the other is in `Params`. 162 154 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); 155 if (o.data.resnSlots) { 156 if (data.resnSlots) { 157 data.resnSlots->insert( 158 data.resnSlots->end(), o.data.resnSlots->begin(), o.data.resnSlots->end() ); 159 delete o.data.resnSlots; 173 160 } 174 } else assertf(false, "invalid mode"); 161 else { 162 data.resnSlots = o.data.resnSlots; 163 } 164 o.data.resnSlots = nullptr; 165 } 166 167 if (o.data.inferParams) { 168 if (data.inferParams) { 169 for ( const auto & p : *o.data.inferParams ) { 170 (*data.inferParams)[p.first] = std::move(p.second); 171 } 172 delete o.data.inferParams; 173 } 174 else { 175 data.inferParams = o.data.inferParams; 176 } 177 o.data.inferParams = nullptr; 178 } 175 179 } 176 180 }; … … 185 189 186 190 Expr * set_extension( bool ex ) { extension = ex; return this; } 191 virtual bool get_lvalue() const; 187 192 188 193 virtual const Expr * accept( Visitor & v ) const override = 0; … … 201 206 ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ); 202 207 208 bool get_lvalue() const final; 209 203 210 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 204 211 private: … … 215 222 UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ) 216 223 : Expr( loc ), func( f ), args( std::move(as) ) {} 224 225 bool get_lvalue() const final; 217 226 218 227 /// Creates a new dereference expression … … 291 300 CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {} 292 301 302 bool get_lvalue() const final; 303 293 304 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 294 305 private: … … 338 349 : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); } 339 350 351 bool get_lvalue() const final; 352 340 353 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 341 354 private: … … 352 365 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg ); 353 366 367 bool get_lvalue() const final; 368 354 369 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 355 370 private: 356 371 MemberExpr * clone() const override { return new MemberExpr{ *this }; } 357 372 MUTATE_FRIEND 373 374 // Custructor overload meant only for AST conversion 375 enum NoOpConstruction { NoOpConstructionChosen }; 376 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg, 377 NoOpConstruction overloadSelector ); 378 friend class ::ConverterOldToNew; 379 friend class ::ConverterNewToOld; 358 380 }; 359 381 … … 365 387 VariableExpr( const CodeLocation & loc ); 366 388 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 389 390 bool get_lvalue() const final; 367 391 368 392 /// generates a function pointer for a given function … … 532 556 533 557 CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 ) 534 : Expr( loc ), arg1( a1 ), arg2( a2 ) {} 558 : Expr( loc ), arg1( a1 ), arg2( a2 ) { 559 this->result = a2->result; 560 } 561 562 bool get_lvalue() const final; 535 563 536 564 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 605 633 CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i ); 606 634 635 bool get_lvalue() const final; 636 607 637 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 608 638 private: … … 660 690 661 691 TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i ); 692 693 bool get_lvalue() const final; 662 694 663 695 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Fwd.hpp
rdab09ad rfb0ae06 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 … … 108 108 class FunctionType; 109 109 class ReferenceToType; 110 class StructInstType; 111 class UnionInstType; 112 class EnumInstType; 110 template<typename decl_t> class SueInstType; 111 using StructInstType = SueInstType<StructDecl>; 112 using UnionInstType = SueInstType<UnionDecl>; 113 using EnumInstType = SueInstType<EnumDecl>; 113 114 class TraitInstType; 114 115 class TypeInstType; -
src/AST/GenericSubstitution.cpp
rdab09ad rfb0ae06 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
rdab09ad rfb0ae06 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 { -
src/AST/Node.cpp
rdab09ad rfb0ae06 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 > -
src/AST/Node.hpp
rdab09ad rfb0ae06 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; … … 57 57 template<typename node_t> 58 58 friend node_t * mutate(const node_t * node); 59 template<typename node_t> 60 friend node_t * shallowCopy(const node_t * node); 59 61 60 62 mutable size_t strong_count = 0; … … 69 71 } 70 72 71 void decrement(ast::Node::ref_type ref ) const {73 void decrement(ast::Node::ref_type ref, bool do_delete = true) const { 72 74 switch (ref) { 73 75 case ref_type::strong: strong_count--; break; … … 75 77 } 76 78 77 if( !strong_count && !weak_count) {79 if( do_delete && !strong_count && !weak_count) { 78 80 delete this; 79 81 } … … 94 96 assertf( 95 97 node->weak_count == 0, 96 "Error: mutating node with weak references to it will invalid edsome references"98 "Error: mutating node with weak references to it will invalidate some references" 97 99 ); 98 100 return node->clone(); … … 104 106 // skip mutate if equivalent 105 107 if ( node->*field == val ) return node; 106 108 107 109 // mutate and return 108 110 node_t * ret = mutate( node ); … … 123 125 (ret->*field)[i] = std::forward< field_t >( val ); 124 126 return ret; 127 } 128 129 /// Mutate an entire indexed collection by cloning to accepted value 130 template<typename node_t, typename parent_t, typename coll_t> 131 const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) { 132 for ( unsigned i = 0; i < (node->*field).size(); ++i ) { 133 node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) ); 134 } 135 return node; 125 136 } 126 137 … … 219 230 operator const node_t * () const { _check(); return node; } 220 231 232 const node_t * release() { 233 const node_t * ret = node; 234 if ( node ) { 235 _dec(node, false); 236 node = nullptr; 237 } 238 return ret; 239 } 240 221 241 /// wrapper for convenient access to dynamic_cast 222 242 template<typename o_node_t> 223 243 const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); } 224 244 225 /// wrapper for convenient access to strict_dynamic_cast245 /// Wrapper that makes sure dynamic_cast returns non-null. 226 246 template<typename o_node_t> 227 const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); } 247 const o_node_t * strict_as() const { 248 if (const o_node_t * ret = as<o_node_t>()) return ret; 249 _strict_fail(); 250 } 251 252 /// Wrapper that makes sure dynamic_cast does not fail. 253 template<typename o_node_t, decltype(nullptr) null> 254 const o_node_t * strict_as() const { return node ? strict_as<o_node_t>() : nullptr; } 228 255 229 256 /// Returns a mutable version of the pointer in this node. … … 244 271 245 272 void _inc( const node_t * other ); 246 void _dec( const node_t * other );273 void _dec( const node_t * other, bool do_delete = true ); 247 274 void _check() const; 275 void _strict_fail() const __attribute__((noreturn)); 248 276 249 277 const node_t * node; -
src/AST/Pass.hpp
rdab09ad rfb0ae06 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 : … … 35 35 #include "AST/SymbolTable.hpp" 36 36 37 #include "AST/ForallSubstitutionTable.hpp" 38 37 39 // Private prelude header, needed for some of the magic tricks this class pulls off 38 40 #include "AST/Pass.proto.hpp" … … 46 48 // 47 49 // 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 50 // | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env 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 // | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation 64 67 //------------------------------------------------------------------------------------------------- 65 template< typename pass_t >68 template< typename core_t > 66 69 class Pass final : public ast::Visitor { 67 70 public: 71 using core_type = core_t; 72 using type = Pass<core_t>; 73 68 74 /// Forward any arguments to the pass constructor 69 75 /// Propagate 'this' if necessary 70 76 template< typename... Args > 71 77 Pass( Args &&... args) 72 : pass( std::forward<Args>( args )... )78 : core( std::forward<Args>( args )... ) 73 79 { 74 80 // 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); 81 type * const * visitor = __pass::visitor(core, 0); 77 82 if(visitor) { 78 *const_cast<t his_t**>( visitor ) = this;83 *const_cast<type **>( visitor ) = this; 79 84 } 80 85 } … … 82 87 virtual ~Pass() = default; 83 88 89 /// Construct and run a pass on a translation unit. 90 template< typename... Args > 91 static void run( std::list< ptr<Decl> > & decls, Args &&... args ) { 92 Pass<core_t> visitor( std::forward<Args>( args )... ); 93 accept_all( decls, visitor ); 94 } 95 84 96 /// Storage for the actual pass 85 pass_t pass;97 core_t core; 86 98 87 99 /// Visit function declarations … … 179 191 const ast::TypeSubstitution * visit( const ast::TypeSubstitution * ) override final; 180 192 181 template<typename pass_type>182 friend void accept_all( std::list< ptr<Decl> > & decls, Pass< pass_type>& visitor );193 template<typename core_type> 194 friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor ); 183 195 private: 184 196 185 bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children( pass, 0); return ptr ? *ptr : true; }197 bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; } 186 198 187 199 private: … … 202 214 container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container ); 203 215 216 /// Mutate forall-list, accounting for presence of type substitution map 217 template<typename node_t> 218 void mutate_forall( const node_t *& ); 219 204 220 public: 205 221 /// Logic to call the accept and mutate the parent if needed, delegates call to accept … … 210 226 /// Internal RAII guard for symbol table features 211 227 struct guard_symtab { 212 guard_symtab( Pass< pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }213 ~guard_symtab() { __pass::symtab::leave(pass , 0); }214 Pass< pass_t> & pass;228 guard_symtab( Pass<core_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.core, 0); } 229 ~guard_symtab() { __pass::symtab::leave(pass.core, 0); } 230 Pass<core_t> & pass; 215 231 }; 216 232 217 233 /// Internal RAII guard for scope features 218 234 struct guard_scope { 219 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); } 220 ~guard_scope() { __pass::scope::leave(pass, 0); } 221 Pass<pass_t> & pass; 235 guard_scope( Pass<core_t> & pass ): pass( pass ) { __pass::scope::enter(pass.core, 0); } 236 ~guard_scope() { __pass::scope::leave(pass.core, 0); } 237 Pass<core_t> & pass; 238 }; 239 240 /// Internal RAII guard for forall substitutions 241 struct guard_forall_subs { 242 guard_forall_subs( Pass<core_t> & pass, const ParameterizedType * type ) 243 : pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); } 244 ~guard_forall_subs() { __pass::forall::leave(pass.core, 0, type ); } 245 Pass<core_t> & pass; 246 const ParameterizedType * type; 222 247 }; 223 248 … … 227 252 228 253 /// Apply a pass to an entire translation unit 229 template<typename pass_t>230 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass< pass_t> & visitor );254 template<typename core_t> 255 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor ); 231 256 232 257 //------------------------------------------------------------------------------------------------- … … 268 293 }; 269 294 270 template< typename pass_t>271 friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );295 template< typename core_t> 296 friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup ); 272 297 public: 273 298 … … 305 330 306 331 /// Used to get a pointer to the pass with its wrapped type 307 template<typename pass_t>332 template<typename core_t> 308 333 struct WithVisitorRef { 309 Pass< pass_t> * const visitor = nullptr;334 Pass<core_t> * const visitor = nullptr; 310 335 }; 311 336 … … 314 339 SymbolTable symtab; 315 340 }; 341 342 /// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl 343 struct WithForallSubstitutor { 344 ForallSubstitutionTable subs; 345 }; 346 316 347 } 317 348 … … 321 352 extern struct PassVisitorStats { 322 353 size_t depth = 0; 323 Stats::Counters::MaxCounter<double> * max = nullptr;324 Stats::Counters::AverageCounter<double> * avg = nullptr;354 Stats::Counters::MaxCounter<double> * max; 355 Stats::Counters::AverageCounter<double> * avg; 325 356 } pass_visitor_stats; 326 357 } -
src/AST/Pass.impl.hpp
rdab09ad rfb0ae06 25 25 using namespace ast; \ 26 26 /* back-up the visit children */ \ 27 __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children( pass, 0) ); \27 __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \ 28 28 /* 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) ); \ 29 __attribute__((unused)) ast::__pass::guard_value guard2( ast::__pass::at_cleanup (core, 0) ); \ 30 /* begin tracing memory allocation if requested by this pass */ \ 31 __pass::beginTrace( core, 0 ); \ 30 32 /* call the implementation of the previsit of this pass */ \ 31 __pass::previsit( pass, node, 0 );33 __pass::previsit( core, node, 0 ); 32 34 33 35 #define VISIT( code... ) \ … … 40 42 #define VISIT_END( type, node ) \ 41 43 /* call the implementation of the postvisit of this pass */ \ 42 auto __return = __pass::postvisit( pass, node, 0 ); \44 auto __return = __pass::postvisit( core, node, 0 ); \ 43 45 assertf(__return, "post visit should never return null"); \ 46 /* end tracing memory allocation if requested by this pass */ \ 47 __pass::endTrace( core, 0 ); \ 44 48 return __return; 45 49 … … 119 123 } 120 124 121 template< typename pass_t >125 template< typename core_t > 122 126 template< typename node_t > 123 auto ast::Pass< pass_t >::call_accept( const node_t * node )127 auto ast::Pass< core_t >::call_accept( const node_t * node ) 124 128 -> typename std::enable_if< 125 129 !std::is_base_of<ast::Expr, node_t>::value && … … 127 131 , decltype( node->accept(*this) ) 128 132 >::type 129 130 133 { 131 134 __pedantic_pass_assert( __visit_children() ); 132 __pedantic_pass_assert( expr);135 __pedantic_pass_assert( node ); 133 136 134 137 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR"); … … 138 141 } 139 142 140 template< typename pass_t >141 const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {143 template< typename core_t > 144 const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) { 142 145 __pedantic_pass_assert( __visit_children() ); 143 146 __pedantic_pass_assert( expr ); 144 147 145 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);148 const ast::TypeSubstitution ** env_ptr = __pass::env( core, 0); 146 149 if ( env_ptr && expr->env ) { 147 150 *env_ptr = expr->env; … … 151 154 } 152 155 153 template< typename pass_t >154 const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {156 template< typename core_t > 157 const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) { 155 158 __pedantic_pass_assert( __visit_children() ); 156 159 __pedantic_pass_assert( stmt ); … … 160 163 161 164 // 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);165 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 166 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 167 auto decls_before = __pass::declsToAddBefore( core, 0); 168 auto decls_after = __pass::declsToAddAfter ( core, 0); 166 169 167 170 // 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) );171 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::env( core, 0) ); 169 172 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 170 173 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); … … 202 205 } 203 206 204 template< typename pass_t >207 template< typename core_t > 205 208 template< template <class...> class container_t > 206 container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {209 container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 207 210 __pedantic_pass_assert( __visit_children() ); 208 211 if( statements.empty() ) return {}; … … 215 218 216 219 // 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);220 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 221 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 222 auto decls_before = __pass::declsToAddBefore( core, 0); 223 auto decls_after = __pass::declsToAddAfter ( core, 0); 221 224 222 225 // These may be modified by subnode but most be restored once we exit this statemnet. … … 268 271 } 269 272 270 template< typename pass_t >273 template< typename core_t > 271 274 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 ) {275 container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 273 276 __pedantic_pass_assert( __visit_children() ); 274 277 if( container.empty() ) return {}; … … 299 302 } 300 303 301 template< typename pass_t >304 template< typename core_t > 302 305 template<typename node_t, typename parent_t, typename child_t> 303 void ast::Pass< pass_t >::maybe_accept(306 void ast::Pass< core_t >::maybe_accept( 304 307 const node_t * & parent, 305 308 child_t parent_t::*child … … 323 326 } 324 327 328 329 template< typename core_t > 330 template< typename node_t > 331 void ast::Pass< core_t >::mutate_forall( const node_t *& node ) { 332 if ( auto subs = __pass::forall::subs( core, 0 ) ) { 333 // tracking TypeDecl substitution, full clone 334 if ( node->forall.empty() ) return; 335 336 node_t * mut = mutate( node ); 337 mut->forall = subs->clone( node->forall, *this ); 338 node = mut; 339 } else { 340 // not tracking TypeDecl substitution, just mutate 341 maybe_accept( node, &node_t::forall ); 342 } 343 } 325 344 } 326 345 … … 333 352 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 334 353 335 template< typename pass_t >336 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {354 template< typename core_t > 355 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) { 337 356 // We are going to aggregate errors for all these statements 338 357 SemanticErrorException errors; … … 342 361 343 362 // 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);363 auto decls_before = __pass::declsToAddBefore( visitor.core, 0); 364 auto decls_after = __pass::declsToAddAfter ( visitor.core, 0); 346 365 347 366 // update pass statitistics … … 392 411 //-------------------------------------------------------------------------- 393 412 // ObjectDecl 394 template< typename pass_t >395 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {413 template< typename core_t > 414 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) { 396 415 VISIT_START( node ); 397 416 … … 406 425 ) 407 426 408 __pass::symtab::addId( pass, 0, node );427 __pass::symtab::addId( core, 0, node ); 409 428 410 429 VISIT_END( DeclWithType, node ); … … 413 432 //-------------------------------------------------------------------------- 414 433 // 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 );434 template< typename core_t > 435 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) { 436 VISIT_START( node ); 437 438 __pass::symtab::addId( core, 0, node ); 420 439 421 440 VISIT(maybe_accept( node, &FunctionDecl::withExprs );) … … 425 444 // shadow with exprs and not the other way around. 426 445 guard_symtab guard { *this }; 427 __pass::symtab::addWith( pass, 0, node->withExprs, node );446 __pass::symtab::addWith( core, 0, node->withExprs, node ); 428 447 { 429 448 guard_symtab guard { *this }; 430 449 // 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 ) ),450 static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{ 451 CodeLocation{}, "__func__", 452 new ast::ArrayType{ 453 new ast::BasicType{ ast::BasicType::Char, ast::CV::Const }, 435 454 nullptr, VariableLen, DynamicDim 436 )437 );438 __pass::symtab::addId( pass, 0, &func );455 } 456 } }; 457 __pass::symtab::addId( core, 0, func ); 439 458 VISIT( 440 459 maybe_accept( node, &FunctionDecl::type ); … … 454 473 //-------------------------------------------------------------------------- 455 474 // StructDecl 456 template< typename pass_t >457 const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {475 template< typename core_t > 476 const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) { 458 477 VISIT_START( node ); 459 478 460 479 // make up a forward declaration and add it before processing the members 461 480 // needs to be on the heap because addStruct saves the pointer 462 __pass::symtab::addStructFwd( pass, 0, node );481 __pass::symtab::addStructFwd( core, 0, node ); 463 482 464 483 VISIT({ … … 469 488 470 489 // this addition replaces the forward declaration 471 __pass::symtab::addStruct( pass, 0, node );490 __pass::symtab::addStruct( core, 0, node ); 472 491 473 492 VISIT_END( Decl, node ); … … 476 495 //-------------------------------------------------------------------------- 477 496 // UnionDecl 478 template< typename pass_t >479 const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {497 template< typename core_t > 498 const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) { 480 499 VISIT_START( node ); 481 500 482 501 // make up a forward declaration and add it before processing the members 483 __pass::symtab::addUnionFwd( pass, 0, node );502 __pass::symtab::addUnionFwd( core, 0, node ); 484 503 485 504 VISIT({ … … 489 508 }) 490 509 491 __pass::symtab::addUnion( pass, 0, node );510 __pass::symtab::addUnion( core, 0, node ); 492 511 493 512 VISIT_END( Decl, node ); … … 496 515 //-------------------------------------------------------------------------- 497 516 // 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 );517 template< typename core_t > 518 const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) { 519 VISIT_START( node ); 520 521 __pass::symtab::addEnum( core, 0, node ); 503 522 504 523 VISIT( … … 513 532 //-------------------------------------------------------------------------- 514 533 // TraitDecl 515 template< typename pass_t >516 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {534 template< typename core_t > 535 const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) { 517 536 VISIT_START( node ); 518 537 … … 523 542 }) 524 543 525 __pass::symtab::addTrait( pass, 0, node );544 __pass::symtab::addTrait( core, 0, node ); 526 545 527 546 VISIT_END( Decl, node ); … … 530 549 //-------------------------------------------------------------------------- 531 550 // TypeDecl 532 template< typename pass_t >533 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {551 template< typename core_t > 552 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) { 534 553 VISIT_START( node ); 535 554 … … 543 562 // note that assertions come after the type is added to the symtab, since they are not part of the type proper 544 563 // and may depend on the type itself 545 __pass::symtab::addType( pass, 0, node );564 __pass::symtab::addType( core, 0, node ); 546 565 547 566 VISIT( … … 559 578 //-------------------------------------------------------------------------- 560 579 // TypedefDecl 561 template< typename pass_t >562 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {580 template< typename core_t > 581 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) { 563 582 VISIT_START( node ); 564 583 … … 569 588 }) 570 589 571 __pass::symtab::addType( pass, 0, node );590 __pass::symtab::addType( core, 0, node ); 572 591 573 592 VISIT( maybe_accept( node, &TypedefDecl::assertions ); ) … … 578 597 //-------------------------------------------------------------------------- 579 598 // AsmDecl 580 template< typename pass_t >581 const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {599 template< typename core_t > 600 const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) { 582 601 VISIT_START( node ); 583 602 … … 591 610 //-------------------------------------------------------------------------- 592 611 // StaticAssertDecl 593 template< typename pass_t >594 const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {612 template< typename core_t > 613 const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) { 595 614 VISIT_START( node ); 596 615 … … 605 624 //-------------------------------------------------------------------------- 606 625 // CompoundStmt 607 template< typename pass_t >608 const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {626 template< typename core_t > 627 const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) { 609 628 VISIT_START( node ); 610 629 VISIT({ 611 630 // 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);631 auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() { 632 if ( ! inFunctionCpy ) __pass::symtab::enter(core, 0); 633 }, [this, inFunctionCpy = this->inFunction]() { 634 if ( ! inFunctionCpy ) __pass::symtab::leave(core, 0); 616 635 }); 617 636 ValueGuard< bool > guard2( inFunction ); … … 625 644 //-------------------------------------------------------------------------- 626 645 // ExprStmt 627 template< typename pass_t >628 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {646 template< typename core_t > 647 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) { 629 648 VISIT_START( node ); 630 649 … … 638 657 //-------------------------------------------------------------------------- 639 658 // AsmStmt 640 template< typename pass_t >641 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {659 template< typename core_t > 660 const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) { 642 661 VISIT_START( node ) 643 662 … … 654 673 //-------------------------------------------------------------------------- 655 674 // DirectiveStmt 656 template< typename pass_t >657 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {675 template< typename core_t > 676 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) { 658 677 VISIT_START( node ) 659 678 … … 663 682 //-------------------------------------------------------------------------- 664 683 // IfStmt 665 template< typename pass_t >666 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {684 template< typename core_t > 685 const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) { 667 686 VISIT_START( node ); 668 687 … … 681 700 //-------------------------------------------------------------------------- 682 701 // WhileStmt 683 template< typename pass_t >684 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {702 template< typename core_t > 703 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) { 685 704 VISIT_START( node ); 686 705 … … 698 717 //-------------------------------------------------------------------------- 699 718 // ForStmt 700 template< typename pass_t >701 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {719 template< typename core_t > 720 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) { 702 721 VISIT_START( node ); 703 722 … … 716 735 //-------------------------------------------------------------------------- 717 736 // SwitchStmt 718 template< typename pass_t >719 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {737 template< typename core_t > 738 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) { 720 739 VISIT_START( node ); 721 740 … … 730 749 //-------------------------------------------------------------------------- 731 750 // CaseStmt 732 template< typename pass_t >733 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {751 template< typename core_t > 752 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) { 734 753 VISIT_START( node ); 735 754 … … 744 763 //-------------------------------------------------------------------------- 745 764 // BranchStmt 746 template< typename pass_t >747 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {765 template< typename core_t > 766 const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) { 748 767 VISIT_START( node ); 749 768 VISIT_END( Stmt, node ); … … 752 771 //-------------------------------------------------------------------------- 753 772 // ReturnStmt 754 template< typename pass_t >755 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {773 template< typename core_t > 774 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) { 756 775 VISIT_START( node ); 757 776 … … 765 784 //-------------------------------------------------------------------------- 766 785 // ThrowStmt 767 template< typename pass_t >768 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {786 template< typename core_t > 787 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) { 769 788 VISIT_START( node ); 770 789 … … 779 798 //-------------------------------------------------------------------------- 780 799 // TryStmt 781 template< typename pass_t >782 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {800 template< typename core_t > 801 const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) { 783 802 VISIT_START( node ); 784 803 … … 794 813 //-------------------------------------------------------------------------- 795 814 // CatchStmt 796 template< typename pass_t >797 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {815 template< typename core_t > 816 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) { 798 817 VISIT_START( node ); 799 818 … … 811 830 //-------------------------------------------------------------------------- 812 831 // FinallyStmt 813 template< typename pass_t >814 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {832 template< typename core_t > 833 const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) { 815 834 VISIT_START( node ); 816 835 … … 824 843 //-------------------------------------------------------------------------- 825 844 // FinallyStmt 826 template< typename pass_t >827 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {845 template< typename core_t > 846 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) { 828 847 VISIT_START( node ); 829 848 … … 837 856 //-------------------------------------------------------------------------- 838 857 // WaitForStmt 839 template< typename pass_t >840 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {858 template< typename core_t > 859 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) { 841 860 VISIT_START( node ); 842 861 // for( auto & clause : node->clauses ) { … … 906 925 //-------------------------------------------------------------------------- 907 926 // WithStmt 908 template< typename pass_t >909 const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {927 template< typename core_t > 928 const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) { 910 929 VISIT_START( node ); 911 930 … … 915 934 // catch statements introduce a level of scope (for the caught exception) 916 935 guard_symtab guard { *this }; 917 __pass::symtab::addWith( pass, 0, node->exprs, node );936 __pass::symtab::addWith( core, 0, node->exprs, node ); 918 937 maybe_accept( node, &WithStmt::stmt ); 919 938 } … … 924 943 //-------------------------------------------------------------------------- 925 944 // NullStmt 926 template< typename pass_t >927 const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {945 template< typename core_t > 946 const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) { 928 947 VISIT_START( node ); 929 948 VISIT_END( NullStmt, node ); … … 932 951 //-------------------------------------------------------------------------- 933 952 // DeclStmt 934 template< typename pass_t >935 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {953 template< typename core_t > 954 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) { 936 955 VISIT_START( node ); 937 956 … … 945 964 //-------------------------------------------------------------------------- 946 965 // ImplicitCtorDtorStmt 947 template< typename pass_t >948 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {966 template< typename core_t > 967 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) { 949 968 VISIT_START( node ); 950 969 951 970 // For now this isn't visited, it is unclear if this causes problem 952 971 // if all tests are known to pass, remove this code 953 //VISIT(954 //maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );955 //)972 VISIT( 973 maybe_accept( node, &ImplicitCtorDtorStmt::callStmt ); 974 ) 956 975 957 976 VISIT_END( Stmt, node ); … … 960 979 //-------------------------------------------------------------------------- 961 980 // ApplicationExpr 962 template< typename pass_t >963 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {981 template< typename core_t > 982 const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) { 964 983 VISIT_START( node ); 965 984 … … 978 997 //-------------------------------------------------------------------------- 979 998 // UntypedExpr 980 template< typename pass_t >981 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {999 template< typename core_t > 1000 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) { 982 1001 VISIT_START( node ); 983 1002 … … 996 1015 //-------------------------------------------------------------------------- 997 1016 // NameExpr 998 template< typename pass_t >999 const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {1017 template< typename core_t > 1018 const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) { 1000 1019 VISIT_START( node ); 1001 1020 … … 1010 1029 //-------------------------------------------------------------------------- 1011 1030 // CastExpr 1012 template< typename pass_t >1013 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {1031 template< typename core_t > 1032 const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) { 1014 1033 VISIT_START( node ); 1015 1034 … … 1026 1045 //-------------------------------------------------------------------------- 1027 1046 // KeywordCastExpr 1028 template< typename pass_t >1029 const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {1047 template< typename core_t > 1048 const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) { 1030 1049 VISIT_START( node ); 1031 1050 … … 1042 1061 //-------------------------------------------------------------------------- 1043 1062 // VirtualCastExpr 1044 template< typename pass_t >1045 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {1063 template< typename core_t > 1064 const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) { 1046 1065 VISIT_START( node ); 1047 1066 … … 1058 1077 //-------------------------------------------------------------------------- 1059 1078 // AddressExpr 1060 template< typename pass_t >1061 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {1079 template< typename core_t > 1080 const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) { 1062 1081 VISIT_START( node ); 1063 1082 … … 1074 1093 //-------------------------------------------------------------------------- 1075 1094 // LabelAddressExpr 1076 template< typename pass_t >1077 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {1095 template< typename core_t > 1096 const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) { 1078 1097 VISIT_START( node ); 1079 1098 … … 1088 1107 //-------------------------------------------------------------------------- 1089 1108 // UntypedMemberExpr 1090 template< typename pass_t >1091 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {1109 template< typename core_t > 1110 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) { 1092 1111 VISIT_START( node ); 1093 1112 … … 1105 1124 //-------------------------------------------------------------------------- 1106 1125 // MemberExpr 1107 template< typename pass_t >1108 const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {1126 template< typename core_t > 1127 const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) { 1109 1128 VISIT_START( node ); 1110 1129 … … 1121 1140 //-------------------------------------------------------------------------- 1122 1141 // VariableExpr 1123 template< typename pass_t >1124 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {1142 template< typename core_t > 1143 const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) { 1125 1144 VISIT_START( node ); 1126 1145 … … 1135 1154 //-------------------------------------------------------------------------- 1136 1155 // ConstantExpr 1137 template< typename pass_t >1138 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {1156 template< typename core_t > 1157 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) { 1139 1158 VISIT_START( node ); 1140 1159 … … 1149 1168 //-------------------------------------------------------------------------- 1150 1169 // SizeofExpr 1151 template< typename pass_t >1152 const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {1170 template< typename core_t > 1171 const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) { 1153 1172 VISIT_START( node ); 1154 1173 … … 1169 1188 //-------------------------------------------------------------------------- 1170 1189 // AlignofExpr 1171 template< typename pass_t >1172 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {1190 template< typename core_t > 1191 const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) { 1173 1192 VISIT_START( node ); 1174 1193 … … 1189 1208 //-------------------------------------------------------------------------- 1190 1209 // UntypedOffsetofExpr 1191 template< typename pass_t >1192 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {1210 template< typename core_t > 1211 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) { 1193 1212 VISIT_START( node ); 1194 1213 … … 1205 1224 //-------------------------------------------------------------------------- 1206 1225 // OffsetofExpr 1207 template< typename pass_t >1208 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {1226 template< typename core_t > 1227 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) { 1209 1228 VISIT_START( node ); 1210 1229 … … 1221 1240 //-------------------------------------------------------------------------- 1222 1241 // OffsetPackExpr 1223 template< typename pass_t >1224 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {1242 template< typename core_t > 1243 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) { 1225 1244 VISIT_START( node ); 1226 1245 … … 1237 1256 //-------------------------------------------------------------------------- 1238 1257 // LogicalExpr 1239 template< typename pass_t >1240 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {1258 template< typename core_t > 1259 const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) { 1241 1260 VISIT_START( node ); 1242 1261 … … 1254 1273 //-------------------------------------------------------------------------- 1255 1274 // ConditionalExpr 1256 template< typename pass_t >1257 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {1275 template< typename core_t > 1276 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) { 1258 1277 VISIT_START( node ); 1259 1278 … … 1272 1291 //-------------------------------------------------------------------------- 1273 1292 // CommaExpr 1274 template< typename pass_t >1275 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {1293 template< typename core_t > 1294 const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) { 1276 1295 VISIT_START( node ); 1277 1296 … … 1289 1308 //-------------------------------------------------------------------------- 1290 1309 // TypeExpr 1291 template< typename pass_t >1292 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {1310 template< typename core_t > 1311 const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) { 1293 1312 VISIT_START( node ); 1294 1313 … … 1305 1324 //-------------------------------------------------------------------------- 1306 1325 // AsmExpr 1307 template< typename pass_t >1308 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {1326 template< typename core_t > 1327 const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) { 1309 1328 VISIT_START( node ); 1310 1329 … … 1322 1341 //-------------------------------------------------------------------------- 1323 1342 // ImplicitCopyCtorExpr 1324 template< typename pass_t >1325 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {1343 template< typename core_t > 1344 const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) { 1326 1345 VISIT_START( node ); 1327 1346 … … 1338 1357 //-------------------------------------------------------------------------- 1339 1358 // ConstructorExpr 1340 template< typename pass_t >1341 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {1359 template< typename core_t > 1360 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) { 1342 1361 VISIT_START( node ); 1343 1362 … … 1354 1373 //-------------------------------------------------------------------------- 1355 1374 // CompoundLiteralExpr 1356 template< typename pass_t >1357 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {1375 template< typename core_t > 1376 const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) { 1358 1377 VISIT_START( node ); 1359 1378 … … 1370 1389 //-------------------------------------------------------------------------- 1371 1390 // RangeExpr 1372 template< typename pass_t >1373 const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {1391 template< typename core_t > 1392 const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) { 1374 1393 VISIT_START( node ); 1375 1394 … … 1387 1406 //-------------------------------------------------------------------------- 1388 1407 // UntypedTupleExpr 1389 template< typename pass_t >1390 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {1408 template< typename core_t > 1409 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) { 1391 1410 VISIT_START( node ); 1392 1411 … … 1403 1422 //-------------------------------------------------------------------------- 1404 1423 // TupleExpr 1405 template< typename pass_t >1406 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {1424 template< typename core_t > 1425 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) { 1407 1426 VISIT_START( node ); 1408 1427 … … 1419 1438 //-------------------------------------------------------------------------- 1420 1439 // TupleIndexExpr 1421 template< typename pass_t >1422 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {1440 template< typename core_t > 1441 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) { 1423 1442 VISIT_START( node ); 1424 1443 … … 1435 1454 //-------------------------------------------------------------------------- 1436 1455 // TupleAssignExpr 1437 template< typename pass_t >1438 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {1456 template< typename core_t > 1457 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) { 1439 1458 VISIT_START( node ); 1440 1459 … … 1451 1470 //-------------------------------------------------------------------------- 1452 1471 // StmtExpr 1453 template< typename pass_t >1454 const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {1472 template< typename core_t > 1473 const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) { 1455 1474 VISIT_START( node ); 1456 1475 1457 1476 VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr 1458 1477 // get the stmts that will need to be spliced in 1459 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);1460 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);1478 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 1479 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 1461 1480 1462 1481 // These may be modified by subnode but most be restored once we exit this statemnet. 1463 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );1482 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( core, 0) ); 1464 1483 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 1465 1484 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); … … 1479 1498 //-------------------------------------------------------------------------- 1480 1499 // UniqueExpr 1481 template< typename pass_t >1482 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {1500 template< typename core_t > 1501 const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) { 1483 1502 VISIT_START( node ); 1484 1503 … … 1495 1514 //-------------------------------------------------------------------------- 1496 1515 // UntypedInitExpr 1497 template< typename pass_t >1498 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {1516 template< typename core_t > 1517 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) { 1499 1518 VISIT_START( node ); 1500 1519 … … 1512 1531 //-------------------------------------------------------------------------- 1513 1532 // InitExpr 1514 template< typename pass_t >1515 const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {1533 template< typename core_t > 1534 const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) { 1516 1535 VISIT_START( node ); 1517 1536 … … 1529 1548 //-------------------------------------------------------------------------- 1530 1549 // DeletedExpr 1531 template< typename pass_t >1532 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {1550 template< typename core_t > 1551 const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) { 1533 1552 VISIT_START( node ); 1534 1553 … … 1546 1565 //-------------------------------------------------------------------------- 1547 1566 // DefaultArgExpr 1548 template< typename pass_t >1549 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {1567 template< typename core_t > 1568 const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) { 1550 1569 VISIT_START( node ); 1551 1570 … … 1562 1581 //-------------------------------------------------------------------------- 1563 1582 // GenericExpr 1564 template< typename pass_t >1565 const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {1583 template< typename core_t > 1584 const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) { 1566 1585 VISIT_START( node ); 1567 1586 … … 1602 1621 //-------------------------------------------------------------------------- 1603 1622 // VoidType 1604 template< typename pass_t >1605 const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {1623 template< typename core_t > 1624 const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) { 1606 1625 VISIT_START( node ); 1607 1626 … … 1611 1630 //-------------------------------------------------------------------------- 1612 1631 // BasicType 1613 template< typename pass_t >1614 const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {1632 template< typename core_t > 1633 const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) { 1615 1634 VISIT_START( node ); 1616 1635 … … 1620 1639 //-------------------------------------------------------------------------- 1621 1640 // PointerType 1622 template< typename pass_t >1623 const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {1641 template< typename core_t > 1642 const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) { 1624 1643 VISIT_START( node ); 1625 1644 … … 1634 1653 //-------------------------------------------------------------------------- 1635 1654 // ArrayType 1636 template< typename pass_t >1637 const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {1655 template< typename core_t > 1656 const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) { 1638 1657 VISIT_START( node ); 1639 1658 … … 1648 1667 //-------------------------------------------------------------------------- 1649 1668 // ReferenceType 1650 template< typename pass_t >1651 const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {1669 template< typename core_t > 1670 const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) { 1652 1671 VISIT_START( node ); 1653 1672 … … 1661 1680 //-------------------------------------------------------------------------- 1662 1681 // QualifiedType 1663 template< typename pass_t >1664 const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {1682 template< typename core_t > 1683 const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) { 1665 1684 VISIT_START( node ); 1666 1685 … … 1675 1694 //-------------------------------------------------------------------------- 1676 1695 // FunctionType 1677 template< typename pass_t > 1678 const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) { 1679 VISIT_START( node ); 1680 1681 VISIT( 1682 maybe_accept( node, &FunctionType::forall ); 1696 template< typename core_t > 1697 const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) { 1698 VISIT_START( node ); 1699 1700 VISIT({ 1701 guard_forall_subs forall_guard { *this, node }; 1702 mutate_forall( node ); 1683 1703 maybe_accept( node, &FunctionType::returns ); 1684 1704 maybe_accept( node, &FunctionType::params ); 1685 )1705 }) 1686 1706 1687 1707 VISIT_END( Type, node ); … … 1690 1710 //-------------------------------------------------------------------------- 1691 1711 // StructInstType 1692 template< typename pass_t >1693 const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {1694 VISIT_START( node ); 1695 1696 __pass::symtab::addStruct( pass, 0, node->name );1712 template< typename core_t > 1713 const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) { 1714 VISIT_START( node ); 1715 1716 __pass::symtab::addStruct( core, 0, node->name ); 1697 1717 1698 1718 VISIT({ 1699 1719 guard_symtab guard { *this }; 1700 maybe_accept( node, &StructInstType::forall ); 1720 guard_forall_subs forall_guard { *this, node }; 1721 mutate_forall( node ); 1701 1722 maybe_accept( node, &StructInstType::params ); 1702 1723 }) … … 1707 1728 //-------------------------------------------------------------------------- 1708 1729 // UnionInstType 1709 template< typename pass_t >1710 const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {1711 VISIT_START( node ); 1712 1713 __pass::symtab::add Struct( pass, 0, node->name );1714 1715 {1730 template< typename core_t > 1731 const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) { 1732 VISIT_START( node ); 1733 1734 __pass::symtab::addUnion( core, 0, node->name ); 1735 1736 VISIT({ 1716 1737 guard_symtab guard { *this }; 1717 maybe_accept( node, &UnionInstType::forall ); 1738 guard_forall_subs forall_guard { *this, node }; 1739 mutate_forall( node ); 1718 1740 maybe_accept( node, &UnionInstType::params ); 1719 } 1741 }) 1720 1742 1721 1743 VISIT_END( Type, node ); … … 1724 1746 //-------------------------------------------------------------------------- 1725 1747 // EnumInstType 1726 template< typename pass_t > 1727 const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) { 1728 VISIT_START( node ); 1729 1730 VISIT( 1731 maybe_accept( node, &EnumInstType::forall ); 1748 template< typename core_t > 1749 const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) { 1750 VISIT_START( node ); 1751 1752 VISIT({ 1753 guard_forall_subs forall_guard { *this, node }; 1754 mutate_forall( node ); 1732 1755 maybe_accept( node, &EnumInstType::params ); 1733 )1756 }) 1734 1757 1735 1758 VISIT_END( Type, node ); … … 1738 1761 //-------------------------------------------------------------------------- 1739 1762 // TraitInstType 1740 template< typename pass_t > 1741 const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) { 1742 VISIT_START( node ); 1743 1744 VISIT( 1745 maybe_accept( node, &TraitInstType::forall ); 1763 template< typename core_t > 1764 const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) { 1765 VISIT_START( node ); 1766 1767 VISIT({ 1768 guard_forall_subs forall_guard { *this, node }; 1769 mutate_forall( node ); 1746 1770 maybe_accept( node, &TraitInstType::params ); 1747 )1771 }) 1748 1772 1749 1773 VISIT_END( Type, node ); … … 1752 1776 //-------------------------------------------------------------------------- 1753 1777 // TypeInstType 1754 template< typename pass_t > 1755 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) { 1756 VISIT_START( node ); 1757 1758 VISIT( 1759 maybe_accept( node, &TypeInstType::forall ); 1760 maybe_accept( node, &TypeInstType::params ); 1778 template< typename core_t > 1779 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) { 1780 VISIT_START( node ); 1781 1782 VISIT( 1783 { 1784 guard_forall_subs forall_guard { *this, node }; 1785 mutate_forall( node ); 1786 maybe_accept( node, &TypeInstType::params ); 1787 } 1788 // ensure that base re-bound if doing substitution 1789 __pass::forall::replace( core, 0, node ); 1761 1790 ) 1762 1791 … … 1766 1795 //-------------------------------------------------------------------------- 1767 1796 // TupleType 1768 template< typename pass_t >1769 const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {1797 template< typename core_t > 1798 const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) { 1770 1799 VISIT_START( node ); 1771 1800 … … 1780 1809 //-------------------------------------------------------------------------- 1781 1810 // TypeofType 1782 template< typename pass_t >1783 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {1811 template< typename core_t > 1812 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) { 1784 1813 VISIT_START( node ); 1785 1814 … … 1793 1822 //-------------------------------------------------------------------------- 1794 1823 // VarArgsType 1795 template< typename pass_t >1796 const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {1824 template< typename core_t > 1825 const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) { 1797 1826 VISIT_START( node ); 1798 1827 … … 1802 1831 //-------------------------------------------------------------------------- 1803 1832 // ZeroType 1804 template< typename pass_t >1805 const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {1833 template< typename core_t > 1834 const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) { 1806 1835 VISIT_START( node ); 1807 1836 … … 1811 1840 //-------------------------------------------------------------------------- 1812 1841 // OneType 1813 template< typename pass_t >1814 const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {1842 template< typename core_t > 1843 const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) { 1815 1844 VISIT_START( node ); 1816 1845 … … 1820 1849 //-------------------------------------------------------------------------- 1821 1850 // GlobalScopeType 1822 template< typename pass_t >1823 const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {1851 template< typename core_t > 1852 const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) { 1824 1853 VISIT_START( node ); 1825 1854 … … 1830 1859 //-------------------------------------------------------------------------- 1831 1860 // Designation 1832 template< typename pass_t >1833 const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {1861 template< typename core_t > 1862 const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) { 1834 1863 VISIT_START( node ); 1835 1864 … … 1841 1870 //-------------------------------------------------------------------------- 1842 1871 // SingleInit 1843 template< typename pass_t >1844 const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {1872 template< typename core_t > 1873 const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) { 1845 1874 VISIT_START( node ); 1846 1875 … … 1854 1883 //-------------------------------------------------------------------------- 1855 1884 // ListInit 1856 template< typename pass_t >1857 const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {1885 template< typename core_t > 1886 const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) { 1858 1887 VISIT_START( node ); 1859 1888 … … 1868 1897 //-------------------------------------------------------------------------- 1869 1898 // ConstructorInit 1870 template< typename pass_t >1871 const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {1899 template< typename core_t > 1900 const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) { 1872 1901 VISIT_START( node ); 1873 1902 … … 1883 1912 //-------------------------------------------------------------------------- 1884 1913 // Attribute 1885 template< typename pass_t >1886 const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node ) {1914 template< typename core_t > 1915 const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node ) { 1887 1916 VISIT_START( node ); 1888 1917 … … 1896 1925 //-------------------------------------------------------------------------- 1897 1926 // TypeSubstitution 1898 template< typename pass_t >1899 const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {1927 template< typename core_t > 1928 const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) { 1900 1929 VISIT_START( node ); 1901 1930 … … 1907 1936 guard_symtab guard { *this }; 1908 1937 auto new_node = p.second->accept( *this ); 1909 if (new_node != p.second) mutated = false;1938 if (new_node != p.second) mutated = true; 1910 1939 new_map.insert({ p.first, new_node }); 1911 1940 } … … 1923 1952 guard_symtab guard { *this }; 1924 1953 auto new_node = p.second->accept( *this ); 1925 if (new_node != p.second) mutated = false;1954 if (new_node != p.second) mutated = true; 1926 1955 new_map.insert({ p.first, new_node }); 1927 1956 } -
src/AST/Pass.proto.hpp
rdab09ad rfb0ae06 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; 22 24 … … 82 84 }; 83 85 84 std::stack< cleanup_t > cleanups;86 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 85 87 }; 86 88 … … 111 113 /// "Short hand" to check if this is a valid previsit function 112 114 /// Mostly used to make the static_assert look (and print) prettier 113 template<typename pass_t, typename node_t>115 template<typename core_t, typename node_t> 114 116 struct is_valid_previsit { 115 using ret_t = decltype( (( pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );117 using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) ); 116 118 117 119 static constexpr bool value = std::is_void< ret_t >::value || … … 127 129 template<> 128 130 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 );131 template<typename core_t, typename node_t> 132 static inline void result( core_t & core, const node_t * & node ) { 133 core.previsit( node ); 132 134 } 133 135 }; … … 135 137 template<> 136 138 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 );139 template<typename core_t, typename node_t> 140 static inline void result( core_t & core, const node_t * & node ) { 141 node = core.previsit( node ); 140 142 assertf(node, "Previsit must not return NULL"); 141 143 } … … 150 152 template<> 151 153 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 );154 template<typename core_t, typename node_t> 155 static inline const node_t * result( core_t & core, const node_t * & node ) { 156 core.postvisit( node ); 155 157 return node; 156 158 } … … 159 161 template<> 160 162 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 );163 template<typename core_t, typename node_t> 164 static inline auto result( core_t & core, const node_t * & node ) { 165 return core.postvisit( node ); 164 166 } 165 167 }; … … 180 182 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 181 183 // 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() ) {184 template<typename core_t, typename node_t> 185 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 184 186 static_assert( 185 is_valid_previsit< pass_t, node_t>::value,187 is_valid_previsit<core_t, node_t>::value, 186 188 "Previsit may not change the type of the node. It must return its paremeter or void." 187 189 ); … … 189 191 __assign< 190 192 std::is_void< 191 decltype( pass.previsit( node ) )193 decltype( core.previsit( node ) ) 192 194 >::value 193 >::result( pass, node );195 >::result( core, node ); 194 196 } 195 197 196 template<typename pass_t, typename node_t>197 static inline auto previsit( pass_t &, const node_t *, long ) {}198 template<typename core_t, typename node_t> 199 static inline auto previsit( core_t &, const node_t *, long ) {} 198 200 199 201 // 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 ) )202 template<typename core_t, typename node_t> 203 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 204 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 203 205 { 204 206 return __return< 205 207 std::is_void< 206 decltype( pass.postvisit( node ) )208 decltype( core.postvisit( node ) ) 207 209 >::value 208 >::result( pass, node );210 >::result( core, node ); 209 211 } 210 212 211 template<typename pass_t, typename node_t>212 static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }213 template<typename core_t, typename node_t> 214 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 213 215 214 216 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- … … 225 227 // The type is not strictly enforced but does match the accessory 226 228 #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; } \229 template< typename core_t > \ 230 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 229 231 \ 230 template< typename pass_t > \231 static inline default_type * name( pass_t &, long ) { return nullptr; }232 template< typename core_t > \ 233 static inline default_type * name( core_t &, long ) { return nullptr; } 232 234 233 235 // List of fields and their expected types … … 239 241 FIELD_PTR( visit_children, __pass::bool_ref ) 240 242 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 241 FIELD_PTR( visitor, ast::Pass< pass_t> * const )243 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 242 244 243 245 // Remove the macro to make sure we don't clash 244 246 #undef FIELD_PTR 247 248 template< typename core_t > 249 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 250 // Stats::Heap::stacktrace_push(core_t::traceId); 251 } 252 253 template< typename core_t > 254 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 255 // Stats::Heap::stacktrace_pop(); 256 } 257 258 template< typename core_t > 259 static void beginTrace(core_t &, long) {} 260 261 template< typename core_t > 262 static void endTrace(core_t &, long) {} 245 263 246 264 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. … … 248 266 // detect it using the same strategy 249 267 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 automatically268 template<typename core_t> 269 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 270 core.beginScope(); 271 } 272 273 template<typename core_t> 274 static inline void enter( core_t &, long ) {} 275 276 template<typename core_t> 277 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 278 core.endScope(); 279 } 280 281 template<typename core_t> 282 static inline void leave( core_t &, long ) {} 283 } // namespace scope 284 285 // Certain passes desire an up to date symbol table automatically 268 286 // detect the presence of a member name `symtab` and call all the members appropriately 269 287 namespace symtab { 270 288 // 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 ) {}289 template<typename core_t> 290 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 291 core.symtab.enterScope(); 292 } 293 294 template<typename core_t> 295 static inline auto enter( core_t &, long ) {} 296 297 template<typename core_t> 298 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 299 core.symtab.leaveScope(); 300 } 301 302 template<typename core_t> 303 static inline auto leave( core_t &, long ) {} 286 304 287 305 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 288 306 // Create macro to condense these common patterns 289 307 #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 ); \308 template<typename core_t> \ 309 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 310 core.symtab.func( arg ); \ 293 311 } \ 294 312 \ 295 template<typename pass_t> \296 static inline void func( pass_t &, long, type ) {}313 template<typename core_t> \ 314 static inline void func( core_t &, long, type ) {} 297 315 298 316 #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 ); \317 template<typename core_t> \ 318 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 319 core.symtab.func( arg1, arg2 ); \ 302 320 } \ 303 321 \ 304 template<typename pass_t> \305 static inline void func( pass_t &, long, type1, type2 ) {}322 template<typename core_t> \ 323 static inline void func( core_t &, long, type1, type2 ) {} 306 324 307 325 SYMTAB_FUNC1( addId , const DeclWithType * ); … … 311 329 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 312 330 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 313 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Node* );331 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 314 332 315 333 // 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() ) {334 template<typename core_t> 335 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 318 336 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 319 337 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() ) {338 core.symtab.addStruct( fwd ); 339 } 340 341 template<typename core_t> 342 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 343 344 template<typename core_t> 345 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 328 346 UnionDecl * fwd = new UnionDecl( decl->location, decl->name ); 329 347 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 );348 core.symtab.addUnion( fwd ); 349 } 350 351 template<typename core_t> 352 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 353 354 template<typename core_t> 355 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 356 if ( ! core.symtab.lookupStruct( str ) ) { 357 core.symtab.addStruct( str ); 340 358 } 341 359 } 342 360 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 );361 template<typename core_t> 362 static inline void addStruct( core_t &, long, const std::string & ) {} 363 364 template<typename core_t> 365 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 366 if ( ! core.symtab.lookupUnion( str ) ) { 367 core.symtab.addUnion( str ); 350 368 } 351 369 } 352 370 353 template<typename pass_t>354 static inline void addUnion( pass_t &, long, const std::string & ) {}371 template<typename core_t> 372 static inline void addUnion( core_t &, long, const std::string & ) {} 355 373 356 374 #undef SYMTAB_FUNC1 357 375 #undef SYMTAB_FUNC2 358 }; 359 }; 360 }; 376 } // namespace symtab 377 378 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 379 // Detect the presence of a member name `subs` and call all members appropriately 380 namespace forall { 381 // Some simple scoping rules 382 template<typename core_t> 383 static inline auto enter( core_t & core, int, const ast::ParameterizedType * type ) 384 -> decltype( core.subs, void() ) { 385 if ( ! type->forall.empty() ) core.subs.beginScope(); 386 } 387 388 template<typename core_t> 389 static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {} 390 391 template<typename core_t> 392 static inline auto leave( core_t & core, int, const ast::ParameterizedType * type ) 393 -> decltype( core.subs, void() ) { 394 if ( ! type->forall.empty() ) { core.subs.endScope(); } 395 } 396 397 template<typename core_t> 398 static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {} 399 400 // Get the substitution table, if present 401 template<typename core_t> 402 static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) { 403 return &core.subs; 404 } 405 406 template<typename core_t> 407 static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; } 408 409 // Replaces a TypeInstType's base TypeDecl according to the table 410 template<typename core_t> 411 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 412 -> decltype( core.subs, void() ) { 413 inst = ast::mutate_field( 414 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 415 } 416 417 template<typename core_t> 418 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 419 420 } // namespace forall 421 } // namespace __pass 422 } // namespace ast -
src/AST/Print.cpp
rdab09ad rfb0ae06 29 29 30 30 template <typename C, typename... T> 31 constexpr auto make_array(T&&... values) -> 32 array<C,sizeof...(T)> 31 constexpr array<C,sizeof...(T)> make_array(T&&... values) 33 32 { 34 33 return array<C,sizeof...(T)>{ … … 129 128 130 129 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() 130 if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) { 131 os << indent << "with " << inferred.data.resnSlots->size() 135 132 << " pending inference slots" << endl; 136 return; 137 } 138 case ast::Expr::InferUnion::Params: { 133 } 134 if (inferred.data.inferParams && !inferred.data.inferParams->empty()) { 139 135 os << indent << "with inferred parameters " << level << ":" << endl; 140 136 ++indent; 141 for ( const auto & i : inferred.data.inferParams ) {137 for ( const auto & i : *inferred.data.inferParams ) { 142 138 os << indent; 143 short_print( Decl::fromId( i.second.decl ));139 short_print( i.second.declptr ); 144 140 os << endl; 145 141 print( i.second.expr->inferred, level+1 ); 146 142 } 147 143 --indent; 148 return;149 }150 144 } 151 145 } … … 233 227 } 234 228 235 if ( ! short_mode && !node->assertions.empty() ) {229 if ( ! node->assertions.empty() ) { 236 230 os << endl << indent << "... with assertions" << endl; 237 231 ++indent; … … 842 836 virtual const ast::Expr * visit( const ast::CastExpr * node ) override final { 843 837 ++indent; 844 os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;838 os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent; 845 839 safe_print( node->arg ); 846 840 os << endl << indent-1 << "... to:"; -
src/AST/Stmt.hpp
rdab09ad rfb0ae06 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 { … … 412 414 class ImplicitCtorDtorStmt final : public Stmt { 413 415 public: 414 readonly<Stmt> callStmt;416 ptr<Stmt> callStmt; 415 417 416 418 ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt, -
src/AST/Type.cpp
rdab09ad rfb0ae06 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 … … 21 21 22 22 #include "Decl.hpp" 23 #include "ForallSubstitutor.hpp" // for substituteForall 23 24 #include "Init.hpp" 25 #include "Common/utility.h" // for copy, move 24 26 #include "InitTweak/InitTweak.h" // for getPointerBase 25 27 #include "Tuples/Tuples.h" // for isTtype … … 90 92 // GENERATED END 91 93 94 // --- ParameterizedType 95 96 void ParameterizedType::initWithSub( 97 const ParameterizedType & o, Pass< ForallSubstitutor > & sub 98 ) { 99 forall = sub.core( o.forall ); 100 } 101 92 102 // --- FunctionType 103 104 FunctionType::FunctionType( const FunctionType & o ) 105 : ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(), 106 isVarArgs( o.isVarArgs ) { 107 Pass< ForallSubstitutor > sub; 108 initWithSub( o, sub ); // initialize substitution map 109 returns = sub.core( o.returns ); // apply to return and parameter types 110 params = sub.core( o.params ); 111 } 93 112 94 113 namespace { … … 106 125 107 126 // --- ReferenceToType 127 128 void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) { 129 ParameterizedType::initWithSub( o, sub ); // initialize substitution 130 params = sub.core( o.params ); // apply to parameters 131 } 132 133 ReferenceToType::ReferenceToType( const ReferenceToType & o ) 134 : ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ), 135 hoistType( o.hoistType ) { 136 Pass< ForallSubstitutor > sub; 137 initWithSub( o, sub ); 138 } 139 108 140 std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const { 109 141 assertf( aggr(), "Must have aggregate to perform lookup" ); … … 116 148 } 117 149 118 // --- StructInstType 119 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 ) {} 123 124 bool StructInstType::isComplete() const { return base ? base->body : false; } 125 126 // --- UnionInstType 127 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; } 150 // --- SueInstType (StructInstType, UnionInstType, EnumInstType) 151 152 template<typename decl_t> 153 SueInstType<decl_t>::SueInstType( 154 const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 155 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 156 157 template<typename decl_t> 158 bool SueInstType<decl_t>::isComplete() const { 159 return base ? base->body : false; 160 } 161 162 template class SueInstType<StructDecl>; 163 template class SueInstType<UnionDecl>; 164 template class SueInstType<EnumDecl>; 141 165 142 166 // --- TraitInstType 143 167 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 ) {}168 TraitInstType::TraitInstType( 169 const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 170 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 147 171 148 172 // --- TypeInstType 173 174 TypeInstType::TypeInstType( const TypeInstType & o ) 175 : ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) { 176 Pass< ForallSubstitutor > sub; 177 initWithSub( o, sub ); // initialize substitution 178 base = sub.core( o.base ); // apply to base type 179 } 149 180 150 181 void TypeInstType::set_base( const TypeDecl * b ) { … … 158 189 159 190 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q ) 160 : Type( q ), types( std::move(ts) ), members() {191 : Type( q ), types( move(ts) ), members() { 161 192 // This constructor is awkward. `TupleType` needs to contain objects so that members can be 162 193 // named, but members without initializer nodes end up getting constructors, which breaks -
src/AST/Type.hpp
rdab09ad rfb0ae06 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; 38 39 struct ForallSubstitutor; 34 40 35 41 class Type : public Node { … … 44 50 bool is_volatile() const { return qualifiers.is_volatile; } 45 51 bool is_restrict() const { return qualifiers.is_restrict; } 46 bool is_lvalue() const { return qualifiers.is_lvalue; }47 52 bool is_mutex() const { return qualifiers.is_mutex; } 48 53 bool is_atomic() const { return qualifiers.is_atomic; } … … 51 56 Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; } 52 57 Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; } 53 Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }54 58 Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; } 55 59 Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; } … … 163 167 static const char *typeNames[]; 164 168 165 BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 169 BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 166 170 : Type(q, std::move(as)), kind(k) {} 167 171 … … 265 269 /// Base type for potentially forall-qualified types 266 270 class ParameterizedType : public Type { 271 protected: 272 /// initializes forall with substitutor 273 void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub ); 267 274 public: 268 275 using ForallList = std::vector<ptr<TypeDecl>>; … … 276 283 ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} ) 277 284 : Type(q, std::move(as)), forall() {} 285 286 // enforce use of ForallSubstitutor to copy parameterized type 287 ParameterizedType( const ParameterizedType & ) = delete; 288 289 ParameterizedType( ParameterizedType && ) = default; 290 291 // no need to change destructor, and operator= deleted in Node 278 292 279 293 private: … … 301 315 : ParameterizedType(q), returns(), params(), isVarArgs(va) {} 302 316 317 FunctionType( const FunctionType & o ); 318 303 319 /// true if either the parameters or return values contain a tttype 304 320 bool isTtype() const; … … 314 330 /// base class for types that refer to types declared elsewhere (aggregates and typedefs) 315 331 class ReferenceToType : public ParameterizedType { 332 protected: 333 /// Initializes forall and parameters based on substitutor 334 void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ); 316 335 public: 317 336 std::vector<ptr<Expr>> params; … … 319 338 bool hoistType = false; 320 339 321 ReferenceToType( const std::string& n, CV::Qualifiers q = {},322 std::vector<ptr<Attribute>> && as = {} )340 ReferenceToType( 341 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 323 342 : ParameterizedType(q, std::move(as)), params(), name(n) {} 343 344 ReferenceToType( const ReferenceToType & o ); 324 345 325 346 /// Gets aggregate declaration this type refers to … … 333 354 }; 334 355 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 = {} ) 356 // Common implementation for the SUE instance types. Not to be used directly. 357 template<typename decl_t> 358 class SueInstType final : public ReferenceToType { 359 public: 360 using base_type = decl_t; 361 readonly<decl_t> base; 362 363 SueInstType( 364 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 342 365 : ReferenceToType( n, q, std::move(as) ), base() {} 343 StructInstType( const StructDecl * b, CV::Qualifiers q = {}, 344 std::vector<ptr<Attribute>> && as = {} ); 366 367 SueInstType( 368 const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 345 369 346 370 bool isComplete() const override; 347 371 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 = {} ) 372 const decl_t * aggr() const override { return base; } 373 374 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 375 private: 376 SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; } 377 MUTATE_FRIEND 378 }; 379 380 /// An instance of a struct type. 381 using StructInstType = SueInstType<StructDecl>; 382 383 /// An instance of a union type. 384 using UnionInstType = SueInstType<UnionDecl>; 385 386 /// An instance of an enum type. 387 using EnumInstType = SueInstType<EnumDecl>; 388 389 /// An instance of a trait type. 390 class TraitInstType final : public ReferenceToType { 391 public: 392 readonly<TraitDecl> base; 393 394 TraitInstType( 395 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 363 396 : 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 { 400 public: 401 readonly<TraitDecl> base; 402 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 = {} ); 397 398 TraitInstType( 399 const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 408 400 409 401 // not meaningful for TraitInstType … … 424 416 TypeDecl::Kind kind; 425 417 426 TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 418 TypeInstType( 419 const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 427 420 std::vector<ptr<Attribute>> && as = {} ) 428 421 : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {} … … 431 424 : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {} 432 425 426 TypeInstType( const TypeInstType & o ); 427 433 428 /// sets `base`, updating `kind` correctly 434 429 void set_base( const TypeDecl * ); -
src/AST/TypeEnvironment.cpp
rdab09ad rfb0ae06 59 59 std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) ); 60 60 out << ")"; 61 61 62 62 if ( clz.bound ) { 63 63 out << " -> "; … … 92 92 } 93 93 } 94 94 95 95 i = next; // go to next node even if this removed 96 96 } … … 161 161 Pass<Occurs> occur{ var, env }; 162 162 maybe_accept( ty, occur ); 163 return occur. pass.result;164 } 165 } 166 167 bool TypeEnvironment::combine( 163 return occur.core.result; 164 } 165 } 166 167 bool TypeEnvironment::combine( 168 168 const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) { 169 169 // short-circuit easy cases … … 199 199 auto st = internal_lookup( *vt ); 200 200 if ( st == env.end() ) { 201 // unbound, safe to add if occurs 201 // unbound, safe to add if occurs 202 202 if ( r.bound && occurs( r.bound, *vt, *this ) ) return false; 203 203 r.vars.emplace( *vt ); … … 266 266 } 267 267 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 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 272 272 ) { 273 273 // remove references from bound type, so that type variables can only bind to value types … … 286 286 ptr<Type> newType = it->bound; 287 287 reset_qualifiers( newType, typeInst->qualifiers ); 288 if ( unifyInexact( 289 newType, target, *this, need, have, open, 288 if ( unifyInexact( 289 newType, target, *this, need, have, open, 290 290 widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) { 291 291 if ( common ) { … … 300 300 } 301 301 } else { 302 env.emplace_back( 302 env.emplace_back( 303 303 typeInst->name, target, widen.first && widen.second, data ); 304 304 } … … 306 306 } 307 307 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 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 312 312 ) { 313 313 auto c1 = internal_lookup( var1->name ); 314 314 auto c2 = internal_lookup( var2->name ); 315 315 316 316 // exit early if variables already bound together 317 317 if ( c1 != env.end() && c1 == c2 ) { … … 396 396 } 397 397 398 bool TypeEnvironment::mergeBound( 398 bool TypeEnvironment::mergeBound( 399 399 EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) { 400 400 if ( from.bound ) { … … 406 406 AssertionSet need, have; 407 407 408 if ( unifyInexact( 408 if ( unifyInexact( 409 409 toType, fromType, *this, need, have, open, widen, symtab, common ) ) { 410 410 // unifies, set common type if necessary … … 424 424 } 425 425 426 bool TypeEnvironment::mergeClasses( 426 bool TypeEnvironment::mergeClasses( 427 427 ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab 428 428 ) { -
src/AST/TypeEnvironment.hpp
rdab09ad rfb0ae06 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 { … … 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 { … … 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 … … 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 -
src/AST/TypeSubstitution.cpp
rdab09ad rfb0ae06 18 18 19 19 namespace ast { 20 21 22 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution"); 20 23 21 24 TypeSubstitution::TypeSubstitution() { … … 92 95 namespace { 93 96 struct EnvTrimmer { 94 ptr<TypeSubstitution>env;97 const TypeSubstitution * env; 95 98 TypeSubstitution * newEnv; 96 99 EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} … … 108 111 if ( env ) { 109 112 TypeSubstitution * newEnv = new TypeSubstitution(); 110 #if TIME_TO_CONVERT_PASSES111 113 Pass<EnvTrimmer> trimmer( env, newEnv ); 112 114 expr->accept( trimmer ); 113 #else114 (void)expr;115 (void)env;116 #endif117 115 return newEnv; 118 116 } … … 121 119 122 120 void TypeSubstitution::normalize() { 123 #if TIME_TO_CONVERT_PASSES 124 PassVisitor<Substituter> sub( *this, true ); 121 Pass<Substituter> sub( *this, true ); 125 122 do { 126 sub. pass.subCount = 0;127 sub. pass.freeOnly = true;123 sub.core.subCount = 0; 124 sub.core.freeOnly = true; 128 125 for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) { 129 i->second = i->second->acceptMutator( sub ); 130 } 131 } while ( sub.pass.subCount ); 132 #endif 133 } 134 135 #if TIME_TO_CONVERT_PASSES 136 137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) { 126 i->second = i->second->accept( sub ); 127 } 128 } while ( sub.core.subCount ); 129 } 130 131 const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) { 138 132 BoundVarsType::const_iterator bound = boundVars.find( inst->name ); 139 133 if ( bound != boundVars.end() ) return inst; … … 146 140 // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here. 147 141 // TODO: investigate preventing type variables from being bound to themselves in the first place. 148 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {142 if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) { 149 143 if ( inst->name == replacement->name ) { 150 144 return inst; … … 153 147 // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl; 154 148 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 ); 160 } // if 161 } 162 163 Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) { 149 ptr<Type> newType = i->second; // force clone if needed 150 add_qualifiers( newType, inst->qualifiers ); 151 // Note: need to recursively apply substitution to the new type because normalize does not 152 // substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 153 newType = newType->accept( *visitor ); 154 return newType.release(); 155 } // if 156 } 157 158 const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) { 164 159 VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name ); 165 160 if ( i == sub.varEnv.end() ) { … … 167 162 } else { 168 163 subCount++; 169 delete nameExpr; 170 return i->second->clone(); 171 } // if 172 } 173 174 void TypeSubstitution::Substituter::premutate( Type * type ) { 164 return i->second; 165 } // if 166 } 167 168 void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) { 175 169 GuardValue( boundVars ); 176 170 // bind type variables from forall-qualifiers 177 171 if ( freeOnly ) { 178 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {179 boundVars.insert( (*tyvar)->name );172 for ( const TypeDecl * tyvar : ptype->forall ) { 173 boundVars.insert( tyvar->name ); 180 174 } // for 181 175 } // if 182 176 } 183 177 184 template< typename TypeClass > 185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) { 178 void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) { 186 179 GuardValue( boundVars ); 187 180 // bind type variables from forall-qualifiers 188 181 if ( freeOnly ) { 189 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {190 boundVars.insert( (*tyvar)->name );182 for ( const TypeDecl * tyvar : type->forall ) { 183 boundVars.insert( tyvar->name ); 191 184 } // for 192 185 // 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 199 } // if 200 } 201 202 void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) { 186 if ( auto decl = type->aggr() ) { 187 if ( ! type->params.empty() ) { 188 for ( const TypeDecl * tyvar : decl->params ) { 189 boundVars.insert( tyvar->name ); 190 } // for 191 } // if 192 } 193 } // if 194 } 195 196 void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) { 203 197 handleAggregateType( aggregateUseType ); 204 198 } 205 199 206 void TypeSubstitution::Substituter::pre mutate(UnionInstType *aggregateUseType ) {200 void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) { 207 201 handleAggregateType( aggregateUseType ); 208 202 } 209 210 #endif211 203 212 204 } // namespace ast -
src/AST/TypeSubstitution.hpp
rdab09ad rfb0ae06 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 // const SynTreeClass * node; 49 ast::ptr<SynTreeClass> node; 50 int count; 51 }; 52 53 template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const; 54 template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const; 48 55 49 56 template< typename node_t, enum Node::ref_type ref_t > 50 57 int apply( ptr_base< node_t, ref_t > & input ) const { 51 58 const node_t * p = input.get(); 52 intret = apply(p);53 input = p;54 return ret ;59 auto ret = apply(p); 60 input = ret.node; 61 return ret.count; 55 62 } 56 63 … … 58 65 int applyFree( ptr_base< node_t, ref_t > & input ) const { 59 66 const node_t * p = input.get(); 60 intret = applyFree(p);61 input = p;62 return ret ;67 auto ret = applyFree(p); 68 input = ret.node; 69 return ret.count; 63 70 } 64 71 … … 92 99 void initialize( const TypeSubstitution &src, TypeSubstitution &dest ); 93 100 94 template<typename pass_type>101 template<typename core_t> 95 102 friend class Pass; 96 103 … … 147 154 // PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals. 148 155 #include "Pass.hpp" 156 #include "Copy.hpp" 149 157 150 158 namespace ast { … … 152 160 // definitition must happen after PassVisitor is included so that WithGuards can be used 153 161 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> { 162 static size_t traceId; 154 163 155 164 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {} 156 165 157 #if TIME_TO_CONVERT_PASSES 158 159 Type * postmutate( TypeInstType * aggregateUseType ); 160 Expression * postmutate( NameExpr * nameExpr ); 166 const Type * postvisit( const TypeInstType * aggregateUseType ); 167 const Expr * postvisit( const NameExpr * nameExpr ); 161 168 162 169 /// Records type variable bindings from forall-statements 163 void pre mutate(Type * type );170 void previsit( const ParameterizedType * type ); 164 171 /// Records type variable bindings from forall-statements and instantiations of generic types 165 template< typename TypeClass > void handleAggregateType( TypeClass * type ); 166 167 void premutate( StructInstType * aggregateUseType ); 168 void premutate( UnionInstType * aggregateUseType ); 169 170 #endif 172 void handleAggregateType( const ReferenceToType * type ); 173 174 void previsit( const StructInstType * aggregateUseType ); 175 void previsit( const UnionInstType * aggregateUseType ); 171 176 172 177 const TypeSubstitution & sub; … … 179 184 180 185 template< typename SynTreeClass > 181 int TypeSubstitution::apply( const SynTreeClass *&input ) const {186 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const { 182 187 assert( input ); 183 188 Pass<Substituter> sub( *this, false ); 184 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; 189 input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) ); 190 return { input, sub.core.subCount }; 189 191 } 190 192 191 193 template< typename SynTreeClass > 192 int TypeSubstitution::applyFree( const SynTreeClass *&input ) const {194 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const { 193 195 assert( input ); 194 196 Pass<Substituter> sub( *this, true ); 195 197 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; 198 return { input, sub.core.subCount }; 200 199 } 201 200 -
src/AST/module.mk
rdab09ad rfb0ae06 22 22 AST/DeclReplacer.cpp \ 23 23 AST/Expr.cpp \ 24 AST/ForallSubstitutionTable.cpp \ 24 25 AST/GenericSubstitution.cpp \ 25 26 AST/Init.cpp \ -
src/AST/porting.md
rdab09ad rfb0ae06 47 47 template<typename node_t> 48 48 friend node_t * mutate(const node_t * node); 49 template<typename node_t> 50 friend node_t * shallowCopy(const node_t * node); 51 or equilant. 52 * You should use the `mutate` function where possible as it avoids extra copies. 53 * If you must copy use `shallowCopy` or `deepCopy` as required. 49 54 50 55 All leaves of the `Node` inheritance tree are now declared `final` -
src/Common/Eval.cc
rdab09ad rfb0ae06 168 168 if (expr) { 169 169 expr->accept(ev); 170 return std::make_pair(ev. pass.value, ev.pass.valid);170 return std::make_pair(ev.core.value, ev.core.valid); 171 171 } else { 172 172 return std::make_pair(0, false); -
src/Common/ScopedMap.h
rdab09ad rfb0ae06 249 249 250 250 /// Gets the note at the given scope 251 Note& getNote() { return scopes.back().note; } 252 const Note& getNote() const { return scopes.back().note; } 251 253 Note& getNote( size_type i ) { return scopes[i].note; } 252 254 const Note& getNote( size_type i ) const { return scopes[i].note; } -
src/Common/Stats/Heap.cc
rdab09ad rfb0ae06 53 53 const size_t passes_size = sizeof(passes) / sizeof(passes[0]); 54 54 size_t passes_cnt = 1; 55 56 StatBlock stacktrace_stats[100]; 57 size_t stacktrace_stats_count = 0; 58 bool stacktrace_stats_enabled = true; 59 60 size_t trace[1000]; 61 const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t); 62 size_t stacktrace_depth; 63 64 size_t new_stacktrace_id(const char * const name) { 65 stacktrace_stats[stacktrace_stats_count].name = name; 66 return stacktrace_stats_count++; 67 } 68 69 void stacktrace_push(size_t id) { 70 ++stacktrace_depth; 71 assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc"); 72 trace[stacktrace_depth] = id; 73 } 74 75 void stacktrace_pop() { 76 assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty"); 77 --stacktrace_depth; 78 } 55 79 56 80 void newPass( const char * const name ) { … … 116 140 for(size_t i = 0; i < passes_cnt; i++) { 117 141 print(passes[i], nc, total_mallocs, total_frees, overall_peak); 142 } 143 144 print('-', nct); 145 std::cerr << std::setw(nc) << "Trace"; 146 std::cerr << " | Malloc Count | Free Count | Peak Allocs |" << std::endl; 147 148 print('-', nct); 149 for (size_t i = 0; i < stacktrace_stats_count; i++) { 150 print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak); 118 151 } 119 152 print('-', nct); … … 188 221 = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs); 189 222 } 223 224 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 225 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 226 } 190 227 return __malloc( size ); 191 228 } … … 196 233 passes[passes_cnt - 1].frees++; 197 234 passes[passes_cnt - 1].n_allocs--; 235 } 236 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 237 stacktrace_stats[trace[stacktrace_depth]].frees++; 198 238 } 199 239 return __free( ptr ); … … 208 248 = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs); 209 249 } 250 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 251 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 252 } 210 253 return __calloc( nelem, size ); 211 254 } … … 218 261 passes[passes_cnt - 1].frees++; 219 262 } // if 263 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 264 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 265 stacktrace_stats[trace[stacktrace_depth]].frees++; 266 } 220 267 return s; 221 268 } -
src/Common/Stats/Heap.h
rdab09ad rfb0ae06 20 20 void newPass( const char * const name ); 21 21 void print(); 22 23 size_t new_stacktrace_id(const char * const name); 24 void stacktrace_push(size_t id); 25 void stacktrace_pop(); 22 26 } 23 27 } -
src/CompilationState.cc
rdab09ad rfb0ae06 14 14 // 15 15 16 #include "config.h" 17 16 18 int 17 19 astp = false, … … 28 30 genproto = false, 29 31 deterministic_output = false, 32 useNewAST = CFA_USE_NEW_AST, 30 33 nomainp = false, 31 34 parsep = false, -
src/CompilationState.h
rdab09ad rfb0ae06 29 29 genproto, 30 30 deterministic_output, 31 useNewAST, 31 32 nomainp, 32 33 parsep, -
src/InitTweak/InitTweak.cc
rdab09ad rfb0ae06 127 127 ast::Pass< InitFlattener_new > flattener; 128 128 maybe_accept( init, flattener ); 129 return std::move( flattener. pass.argList );129 return std::move( flattener.core.argList ); 130 130 } 131 131 … … 561 561 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 562 562 maybe_accept( stmt, finder ); 563 return std::move( finder. pass.matches );563 return std::move( finder.core.matches ); 564 564 } 565 565 -
src/ResolvExpr/AdjustExprType.cc
rdab09ad rfb0ae06 100 100 101 101 namespace { 102 struct AdjustExprType_new final : public ast::WithShortCircuiting { 102 class AdjustExprType_new final : public ast::WithShortCircuiting { 103 const ast::SymbolTable & symtab; 104 public: 103 105 const ast::TypeEnvironment & tenv; 104 const ast::SymbolTable & symtab;105 106 106 107 AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 107 : tenv( e ), symtab( syms) {}108 : symtab( syms ), tenv( e ) {} 108 109 109 void pre mutate( const ast::VoidType * ) { visit_children = false; }110 void pre mutate( const ast::BasicType * ) { visit_children = false; }111 void pre mutate( const ast::PointerType * ) { visit_children = false; }112 void pre mutate( const ast::ArrayType * ) { visit_children = false; }113 void pre mutate( const ast::FunctionType * ) { visit_children = false; }114 void pre mutate( const ast::StructInstType * ) { visit_children = false; }115 void pre mutate( const ast::UnionInstType * ) { visit_children = false; }116 void pre mutate( const ast::EnumInstType * ) { visit_children = false; }117 void pre mutate( const ast::TraitInstType * ) { visit_children = false; }118 void pre mutate( const ast::TypeInstType * ) { visit_children = false; }119 void pre mutate( const ast::TupleType * ) { visit_children = false; }120 void pre mutate( const ast::VarArgsType * ) { visit_children = false; }121 void pre mutate( const ast::ZeroType * ) { visit_children = false; }122 void pre mutate( const ast::OneType * ) { visit_children = false; }110 void previsit( const ast::VoidType * ) { visit_children = false; } 111 void previsit( const ast::BasicType * ) { visit_children = false; } 112 void previsit( const ast::PointerType * ) { visit_children = false; } 113 void previsit( const ast::ArrayType * ) { visit_children = false; } 114 void previsit( const ast::FunctionType * ) { visit_children = false; } 115 void previsit( const ast::StructInstType * ) { visit_children = false; } 116 void previsit( const ast::UnionInstType * ) { visit_children = false; } 117 void previsit( const ast::EnumInstType * ) { visit_children = false; } 118 void previsit( const ast::TraitInstType * ) { visit_children = false; } 119 void previsit( const ast::TypeInstType * ) { visit_children = false; } 120 void previsit( const ast::TupleType * ) { visit_children = false; } 121 void previsit( const ast::VarArgsType * ) { visit_children = false; } 122 void previsit( const ast::ZeroType * ) { visit_children = false; } 123 void previsit( const ast::OneType * ) { visit_children = false; } 123 124 124 const ast::Type * post mutate( const ast::ArrayType * at ) {125 const ast::Type * postvisit( const ast::ArrayType * at ) { 125 126 return new ast::PointerType{ at->base, at->qualifiers }; 126 127 } 127 128 128 const ast::Type * post mutate( const ast::FunctionType * ft ) {129 const ast::Type * postvisit( const ast::FunctionType * ft ) { 129 130 return new ast::PointerType{ ft }; 130 131 } 131 132 132 const ast::Type * post mutate( const ast::TypeInstType * inst ) {133 const ast::Type * postvisit( const ast::TypeInstType * inst ) { 133 134 // replace known function-type-variables with pointer-to-function 134 135 if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) { -
src/ResolvExpr/Candidate.hpp
rdab09ad rfb0ae06 51 51 52 52 Candidate( const ast::Expr * x, const ast::TypeEnvironment & e ) 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {} 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() { 54 assert(x->result); 55 } 54 56 55 57 Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero ) 56 58 : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ), 57 need( o.need ) {} 59 need( o.need ) { 60 assert(x->result); 61 } 58 62 59 63 Candidate( 60 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 64 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 61 65 const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero ) 62 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {} 66 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) { 67 assert(x->result); 68 } 63 69 64 70 Candidate( … … 66 72 ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero ) 67 73 : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ), 68 need( n.begin(), n.end() ) {} 74 need( n.begin(), n.end() ) { 75 assert(x->result); 76 } 69 77 }; 70 78 -
src/ResolvExpr/CandidateFinder.cpp
rdab09ad rfb0ae06 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 14:55:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 54 54 return new ast::CastExpr{ expr, expr->result->stripReferences() }; 55 55 } 56 56 57 57 return expr; 58 58 } … … 61 61 UniqueId globalResnSlot = 0; 62 62 63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,65 const ast:: TypeEnvironment & env63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 65 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 66 66 ) { 67 67 PRINT( … … 74 74 std::cerr << std::endl; 75 75 ) 76 Cost convCost = conversionCost( argType, paramType, symtab, env );76 Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env ); 77 77 PRINT( 78 78 std::cerr << std::endl << "cost is " << convCost << std::endl; … … 107 107 108 108 /// Computes conversion cost for a given expression to a given type 109 const ast::Expr * computeExpressionConversionCost( 110 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 109 const ast::Expr * computeExpressionConversionCost( 110 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 111 111 ) { 112 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env ); 112 Cost convCost = computeConversionCost( 113 arg->result, paramType, arg->get_lvalue(), symtab, env ); 113 114 outCost += convCost; 114 115 115 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 116 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 116 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 117 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 117 118 // infer parameters and this does not currently work for the reason stated below 118 119 Cost tmpCost = convCost; … … 123 124 return new ast::CastExpr{ arg, newType }; 124 125 125 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 126 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 126 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 127 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 127 128 // once this is fixed it should be possible to resolve the cast. 128 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 129 // but it shouldn't be because this makes the conversion from DT* to DT* since 129 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 130 // but it shouldn't be because this makes the conversion from DT* to DT* since 130 131 // commontype(zero_t, DT*) is DT*, rather than nothing 131 132 132 133 // CandidateFinder finder{ symtab, env }; 133 134 // finder.find( arg, ResolvMode::withAdjustment() ); 134 // assertf( finder.candidates.size() > 0, 135 // assertf( finder.candidates.size() > 0, 135 136 // "Somehow castable expression failed to find alternatives." ); 136 // assertf( finder.candidates.size() == 1, 137 // assertf( finder.candidates.size() == 1, 137 138 // "Somehow got multiple alternatives for known cast expression." ); 138 139 // return finder.candidates.front()->expr; … … 143 144 144 145 /// Computes conversion cost for a given candidate 145 Cost computeApplicationConversionCost( 146 CandidateRef cand, const ast::SymbolTable & symtab 146 Cost computeApplicationConversionCost( 147 CandidateRef cand, const ast::SymbolTable & symtab 147 148 ) { 148 149 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); … … 167 168 if ( function->isVarArgs ) { 168 169 convCost.incUnsafe(); 169 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 171 << convCost << std::endl; ; ) 171 172 // convert reference-typed expressions into value-typed expressions 172 cand->expr = ast::mutate_field_index( 173 appExpr, &ast::ApplicationExpr::args, i, 173 cand->expr = ast::mutate_field_index( 174 appExpr, &ast::ApplicationExpr::args, i, 174 175 referenceToRvalueConversion( args[i], convCost ) ); 175 176 continue; … … 180 181 // Default arguments should be free - don't include conversion cost. 181 182 // Unwrap them here because they are not relevant to the rest of the system 182 cand->expr = ast::mutate_field_index( 183 cand->expr = ast::mutate_field_index( 183 184 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 184 185 ++param; … … 188 189 // mark conversion cost and also specialization cost of param type 189 190 const ast::Type * paramType = (*param)->get_type(); 190 cand->expr = ast::mutate_field_index( 191 appExpr, &ast::ApplicationExpr::args, i, 192 computeExpressionConversionCost( 191 cand->expr = ast::mutate_field_index( 192 appExpr, &ast::ApplicationExpr::args, i, 193 computeExpressionConversionCost( 193 194 args[i], paramType, symtab, cand->env, convCost ) ); 194 195 convCost.decSpec( specCost( paramType ) ); … … 198 199 if ( param != params.end() ) return Cost::infinity; 199 200 200 // specialization cost of return types can't be accounted for directly, it disables 201 // specialization cost of return types can't be accounted for directly, it disables 201 202 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 202 203 // … … 215 216 } 216 217 217 void makeUnifiableVars( 218 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 219 ast::AssertionSet & need 218 void makeUnifiableVars( 219 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 220 ast::AssertionSet & need 220 221 ) { 221 222 for ( const ast::TypeDecl * tyvar : type->forall ) { … … 254 255 255 256 ArgPack() 256 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 258 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 258 259 ArgPack( 260 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 259 260 ArgPack( 261 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 261 262 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 262 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 264 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 264 265 265 266 ArgPack( 266 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 267 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 268 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 267 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 268 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 269 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 269 270 unsigned nextExpl = 0, unsigned explAlt = 0 ) 270 271 : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ), 271 272 have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 272 273 nextExpl( nextExpl ), explAlt( explAlt ) {} 273 274 274 275 ArgPack( 275 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 277 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 277 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 278 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 278 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 279 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 279 280 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 280 281 281 282 /// true if this pack is in the middle of an exploded argument 282 283 bool hasExpl() const { return nextExpl > 0; } … … 286 287 return args[ nextArg-1 ][ explAlt ]; 287 288 } 288 289 289 290 /// Ends a tuple expression, consolidating the appropriate args 290 291 void endTuple( const std::vector< ArgPack > & packs ) { … … 307 308 308 309 /// Instantiates an argument to match a parameter, returns false if no matching results left 309 bool instantiateArgument( 310 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 311 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 312 unsigned nTuples = 0 310 bool instantiateArgument( 311 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 312 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 313 unsigned nTuples = 0 313 314 ) { 314 315 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { … … 318 319 // xxx - dropping initializer changes behaviour from previous, but seems correct 319 320 // ^^^ need to handle the case where a tuple has a default argument 320 if ( ! instantiateArgument( 321 if ( ! instantiateArgument( 321 322 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 322 323 nTuples = 0; … … 329 330 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 330 331 // paramType is a ttype, consumes all remaining arguments 331 332 332 333 // completed tuples; will be spliced to end of results to finish 333 334 std::vector< ArgPack > finalResults{}; … … 342 343 for ( std::size_t i = genStart; i < genEnd; ++i ) { 343 344 unsigned nextArg = results[i].nextArg; 344 345 345 346 // use next element of exploded tuple if present 346 347 if ( results[i].hasExpl() ) { … … 352 353 results.emplace_back( 353 354 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 354 copy( results[i].need ), copy( results[i].have ), 355 copy( results[i].need ), copy( results[i].have ), 355 356 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 356 357 results[i].explAlt ); … … 370 371 // push empty tuple expression 371 372 newResult.parent = i; 372 std::vector< ast::ptr< ast::Expr > > emptyList; 373 newResult.expr = 374 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) }; 373 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} }; 375 374 argType = newResult.expr->result; 376 375 } else { … … 400 399 401 400 // check unification for ttype before adding to final 402 if ( 403 unify( 401 if ( 402 unify( 404 403 ttype, argType, newResult.env, newResult.need, newResult.have, 405 newResult.open, symtab ) 404 newResult.open, symtab ) 406 405 ) { 407 406 finalResults.emplace_back( move( newResult ) ); … … 424 423 if ( expl.exprs.empty() ) { 425 424 results.emplace_back( 426 results[i], move( env ), copy( results[i].need ), 425 results[i], move( env ), copy( results[i].need ), 427 426 copy( results[i].have ), move( open ), nextArg + 1, expl.cost ); 428 427 429 428 continue; 430 429 } … … 432 431 // add new result 433 432 results.emplace_back( 434 i, expl.exprs.front(), move( env ), copy( results[i].need ), 435 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 433 i, expl.exprs.front(), move( env ), copy( results[i].need ), 434 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 436 435 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 437 436 } … … 479 478 480 479 results.emplace_back( 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 480 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 482 481 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 483 482 } … … 495 494 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 496 495 results.emplace_back( 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 496 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 498 497 move( need ), move( have ), move( open ), nextArg, nTuples ); 499 498 } … … 517 516 if ( expl.exprs.empty() ) { 518 517 results.emplace_back( 519 results[i], move( env ), move( need ), move( have ), move( open ), 518 results[i], move( env ), move( need ), move( have ), move( open ), 520 519 nextArg + 1, expl.cost ); 521 520 522 521 continue; 523 522 } … … 539 538 // add new result 540 539 results.emplace_back( 541 i, expr, move( env ), move( need ), move( have ), move( open ), 540 i, expr, move( env ), move( need ), move( have ), move( open ), 542 541 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 543 542 } … … 548 547 genStart = genEnd; 549 548 550 return genEnd != results.size(); 549 return genEnd != results.size(); // were any new results added? 551 550 } 552 551 553 552 /// Generate a cast expression from `arg` to `toType` 554 const ast::Expr * restructureCast( 553 const ast::Expr * restructureCast( 555 554 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 556 555 ) { 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 556 if ( 557 arg->result->size() > 1 558 && ! toType->isVoid() 559 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 561 560 ) { 562 // Argument is a tuple and the target type is neither void nor a reference. Cast each 563 // member of the tuple to its corresponding target type, producing the tuple of those 564 // cast expressions. If there are more components of the tuple than components in the 565 // target type, then excess components do not come out in the result expression (but 561 // Argument is a tuple and the target type is neither void nor a reference. Cast each 562 // member of the tuple to its corresponding target type, producing the tuple of those 563 // cast expressions. If there are more components of the tuple than components in the 564 // target type, then excess components do not come out in the result expression (but 566 565 // UniqueExpr ensures that the side effects will still be produced) 567 566 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 568 // expressions which may contain side effects require a single unique instance of 567 // expressions which may contain side effects require a single unique instance of 569 568 // the expression 570 569 arg = new ast::UniqueExpr{ arg->location, arg }; … … 574 573 // cast each component 575 574 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 576 components.emplace_back( 575 components.emplace_back( 577 576 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 578 577 } … … 594 593 595 594 /// Actually visits expressions to find their candidate interpretations 596 struct Finder final : public ast::WithShortCircuiting { 595 class Finder final : public ast::WithShortCircuiting { 596 const ast::SymbolTable & symtab; 597 public: 598 static size_t traceId; 597 599 CandidateFinder & selfFinder; 598 const ast::SymbolTable & symtab;599 600 CandidateList & candidates; 600 601 const ast::TypeEnvironment & tenv; 601 602 ast::ptr< ast::Type > & targetType; 602 603 604 enum Errors { 605 NotFound, 606 NoMatch, 607 ArgsToFew, 608 ArgsToMany, 609 RetsToFew, 610 RetsToMany, 611 NoReason 612 }; 613 614 struct { 615 Errors code = NotFound; 616 } reason; 617 603 618 Finder( CandidateFinder & f ) 604 : s elfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),619 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 605 620 targetType( f.targetType ) {} 606 621 607 622 void previsit( const ast::Node * ) { visit_children = false; } 608 623 … … 611 626 void addCandidate( Args &&... args ) { 612 627 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 628 reason.code = NoReason; 613 629 } 614 630 … … 639 655 640 656 /// Completes a function candidate with arguments located 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 657 void validateFunctionCandidate( 658 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 659 CandidateList & out 644 660 ) { 645 ast::ApplicationExpr * appExpr = 661 ast::ApplicationExpr * appExpr = 646 662 new ast::ApplicationExpr{ func->expr->location, func->expr }; 647 663 // sum cost and accumulate arguments … … 657 673 appExpr->args = move( vargs ); 658 674 // build and validate new candidate 659 auto newCand = 675 auto newCand = 660 676 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 661 677 PRINT( … … 669 685 /// Builds a list of candidates for a function, storing them in out 670 686 void makeFunctionCandidates( 671 const CandidateRef & func, const ast::FunctionType * funcType, 687 const CandidateRef & func, const ast::FunctionType * funcType,