Changes in / [057298e:7030dab]
- Files:
-
- 7 added
- 1 deleted
- 47 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Attribute.hpp
r057298e r7030dab 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
r057298e r7030dab 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
r057298e r7030dab 620 620 621 621 tgt->result = get<Type>().accept1(src->result); 622 // Unconditionally use a clone of the result type. 623 // We know this will leak some objects: much of the immediate conversion result. 624 // In some cases, using the conversion result directly gives unintended object sharing. 625 // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache. 626 // But tgt->result must be fully owned privately by tgt. 627 // Applying these conservative copies here means 628 // - weak references point at the declaration's copy, not these expr.result copies (good) 629 // - we copy more objects than really needed (bad, tolerated) 630 if (tgt->result) { 631 tgt->result = tgt->result->clone(); 632 } 622 633 return visitBaseExpr_skipResultType(src, tgt); 623 634 } … … 2117 2128 old->location, 2118 2129 GET_ACCEPT_1(member, DeclWithType), 2119 GET_ACCEPT_1(aggregate, Expr) 2130 GET_ACCEPT_1(aggregate, Expr), 2131 ast::MemberExpr::NoOpConstructionChosen 2120 2132 ) 2121 2133 ); -
src/AST/Decl.cpp
r057298e r7030dab 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
r057298e r7030dab 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, TypeVar::Kind k, bool s, const Type * i = nullptr ) 194 : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeVar::Ttype || s ), 195 init( i ) {} 192 196 193 197 const char * typeString() const override; -
src/AST/Expr.cpp
r057298e r7030dab 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
r057298e r7030dab 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; … … 185 188 186 189 Expr * set_extension( bool ex ) { extension = ex; return this; } 190 virtual bool get_lvalue() const; 187 191 188 192 virtual const Expr * accept( Visitor & v ) const override = 0; … … 201 205 ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ); 202 206 207 bool get_lvalue() const final; 208 203 209 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 204 210 private: … … 215 221 UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ) 216 222 : Expr( loc ), func( f ), args( std::move(as) ) {} 223 224 bool get_lvalue() const final; 217 225 218 226 /// Creates a new dereference expression … … 291 299 CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {} 292 300 301 bool get_lvalue() const final; 302 293 303 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 294 304 private: … … 338 348 : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); } 339 349 350 bool get_lvalue() const final; 351 340 352 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 341 353 private: … … 352 364 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg ); 353 365 366 bool get_lvalue() const final; 367 354 368 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 355 369 private: 356 370 MemberExpr * clone() const override { return new MemberExpr{ *this }; } 357 371 MUTATE_FRIEND 372 373 // Custructor overload meant only for AST conversion 374 enum NoOpConstruction { NoOpConstructionChosen }; 375 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg, 376 NoOpConstruction overloadSelector ); 377 friend class ::ConverterOldToNew; 378 friend class ::ConverterNewToOld; 358 379 }; 359 380 … … 365 386 VariableExpr( const CodeLocation & loc ); 366 387 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 388 389 bool get_lvalue() const final; 367 390 368 391 /// generates a function pointer for a given function … … 532 555 533 556 CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 ) 534 : Expr( loc ), arg1( a1 ), arg2( a2 ) {} 557 : Expr( loc ), arg1( a1 ), arg2( a2 ) { 558 this->result = a2->result; 559 } 560 561 bool get_lvalue() const final; 535 562 536 563 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 605 632 CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i ); 606 633 634 bool get_lvalue() const final; 635 607 636 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 608 637 private: … … 660 689 661 690 TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i ); 691 692 bool get_lvalue() const final; 662 693 663 694 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Init.hpp
r057298e r7030dab 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
r057298e r7030dab 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 template< typename node_t, enum ast::Node::ref_type ref_t > 46 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { 47 node->increment(ref_t); 48 _trap( node ); 49 } 50 51 template< typename node_t, enum ast::Node::ref_type ref_t > 52 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) { 53 _trap( node ); 54 node->decrement(ref_t, do_delete ); 55 } 56 57 template< typename node_t, enum ast::Node::ref_type ref_t > 58 void ast::ptr_base<node_t, ref_t>::_check() const { 59 // if(node) assert(node->was_ever_strong == false || node->strong_count > 0); 60 } 39 61 40 62 template< typename node_t, enum ast::Node::ref_type ref_t > -
src/AST/Node.hpp
r057298e r7030dab 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> … … 244 264 245 265 void _inc( const node_t * other ); 246 void _dec( const node_t * other );266 void _dec( const node_t * other, bool do_delete = true ); 247 267 void _check() const; 248 268 -
src/AST/Pass.hpp
r057298e r7030dab 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 68 template< typename pass_t > … … 202 205 container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container ); 203 206 207 /// Mutate forall-list, accounting for presence of type substitution map 208 template<typename node_t> 209 void mutate_forall( const node_t *& ); 210 204 211 public: 205 212 /// Logic to call the accept and mutate the parent if needed, delegates call to accept … … 210 217 /// Internal RAII guard for symbol table features 211 218 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); }219 guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.pass, 0); } 220 ~guard_symtab() { __pass::symtab::leave(pass.pass, 0); } 214 221 Pass<pass_t> & pass; 215 222 }; … … 217 224 /// Internal RAII guard for scope features 218 225 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); }226 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass.pass, 0); } 227 ~guard_scope() { __pass::scope::leave(pass.pass, 0); } 221 228 Pass<pass_t> & pass; 229 }; 230 231 /// Internal RAII guard for forall substitutions 232 struct guard_forall_subs { 233 guard_forall_subs( Pass<pass_t> & pass, const ParameterizedType * type ) 234 : pass( pass ), type( type ) { __pass::forall::enter(pass.pass, 0, type ); } 235 ~guard_forall_subs() { __pass::forall::leave(pass.pass, 0, type ); } 236 Pass<pass_t> & pass; 237 const ParameterizedType * type; 222 238 }; 223 239 … … 314 330 SymbolTable symtab; 315 331 }; 332 333 /// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl 334 struct WithForallSubstitutor { 335 ForallSubstitutionTable subs; 336 }; 337 316 338 } 317 339 -
src/AST/Pass.impl.hpp
r057298e r7030dab 127 127 , decltype( node->accept(*this) ) 128 128 >::type 129 130 129 { 131 130 __pedantic_pass_assert( __visit_children() ); 132 __pedantic_pass_assert( expr);131 __pedantic_pass_assert( node ); 133 132 134 133 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR"); … … 323 322 } 324 323 324 325 template< typename pass_t > 326 template< typename node_t > 327 void ast::Pass< pass_t >::mutate_forall( const node_t *& node ) { 328 if ( auto subs = __pass::forall::subs( pass, 0 ) ) { 329 // tracking TypeDecl substitution, full clone 330 if ( node->forall.empty() ) return; 331 332 node_t * mut = mutate( node ); 333 mut->forall = subs->clone( node->forall, *this ); 334 node = mut; 335 } else { 336 // not tracking TypeDecl substitution, just mutate 337 maybe_accept( node, &node_t::forall ); 338 } 339 } 325 340 } 326 341 … … 429 444 guard_symtab guard { *this }; 430 445 // 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 ) ),446 static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{ 447 CodeLocation{}, "__func__", 448 new ast::ArrayType{ 449 new ast::BasicType{ ast::BasicType::Char, ast::CV::Const }, 435 450 nullptr, VariableLen, DynamicDim 436 )437 );438 __pass::symtab::addId( pass, 0, &func );451 } 452 } }; 453 __pass::symtab::addId( pass, 0, func ); 439 454 VISIT( 440 455 maybe_accept( node, &FunctionDecl::type ); … … 610 625 VISIT({ 611 626 // 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);627 auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() { 628 if ( ! inFunctionCpy ) __pass::symtab::enter(pass, 0); 629 }, [this, inFunctionCpy = this->inFunction]() { 630 if ( ! inFunctionCpy ) __pass::symtab::leave(pass, 0); 616 631 }); 617 632 ValueGuard< bool > guard2( inFunction ); … … 951 966 // For now this isn't visited, it is unclear if this causes problem 952 967 // if all tests are known to pass, remove this code 953 //VISIT(954 //maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );955 //)968 VISIT( 969 maybe_accept( node, &ImplicitCtorDtorStmt::callStmt ); 970 ) 956 971 957 972 VISIT_END( Stmt, node ); … … 1679 1694 VISIT_START( node ); 1680 1695 1681 VISIT( 1682 maybe_accept( node, &FunctionType::forall ); 1696 VISIT({ 1697 guard_forall_subs forall_guard { *this, node }; 1698 mutate_forall( node ); 1683 1699 maybe_accept( node, &FunctionType::returns ); 1684 1700 maybe_accept( node, &FunctionType::params ); 1685 )1701 }) 1686 1702 1687 1703 VISIT_END( Type, node ); … … 1698 1714 VISIT({ 1699 1715 guard_symtab guard { *this }; 1700 maybe_accept( node, &StructInstType::forall ); 1716 guard_forall_subs forall_guard { *this, node }; 1717 mutate_forall( node ); 1701 1718 maybe_accept( node, &StructInstType::params ); 1702 1719 }) … … 1711 1728 VISIT_START( node ); 1712 1729 1713 __pass::symtab::add Struct( pass, 0, node->name );1714 1715 {1730 __pass::symtab::addUnion( pass, 0, node->name ); 1731 1732 VISIT({ 1716 1733 guard_symtab guard { *this }; 1717 maybe_accept( node, &UnionInstType::forall ); 1734 guard_forall_subs forall_guard { *this, node }; 1735 mutate_forall( node ); 1718 1736 maybe_accept( node, &UnionInstType::params ); 1719 } 1737 }) 1720 1738 1721 1739 VISIT_END( Type, node ); … … 1728 1746 VISIT_START( node ); 1729 1747 1730 VISIT( 1731 maybe_accept( node, &EnumInstType::forall ); 1748 VISIT({ 1749 guard_forall_subs forall_guard { *this, node }; 1750 mutate_forall( node ); 1732 1751 maybe_accept( node, &EnumInstType::params ); 1733 )1752 }) 1734 1753 1735 1754 VISIT_END( Type, node ); … … 1742 1761 VISIT_START( node ); 1743 1762 1744 VISIT( 1745 maybe_accept( node, &TraitInstType::forall ); 1763 VISIT({ 1764 guard_forall_subs forall_guard { *this, node }; 1765 mutate_forall( node ); 1746 1766 maybe_accept( node, &TraitInstType::params ); 1747 )1767 }) 1748 1768 1749 1769 VISIT_END( Type, node ); … … 1757 1777 1758 1778 VISIT( 1759 maybe_accept( node, &TypeInstType::forall ); 1760 maybe_accept( node, &TypeInstType::params ); 1779 { 1780 guard_forall_subs forall_guard { *this, node }; 1781 mutate_forall( node ); 1782 maybe_accept( node, &TypeInstType::params ); 1783 } 1784 // ensure that base re-bound if doing substitution 1785 __pass::forall::replace( pass, 0, node ); 1761 1786 ) 1762 1787 … … 1907 1932 guard_symtab guard { *this }; 1908 1933 auto new_node = p.second->accept( *this ); 1909 if (new_node != p.second) mutated = false;1934 if (new_node != p.second) mutated = true; 1910 1935 new_map.insert({ p.first, new_node }); 1911 1936 } … … 1923 1948 guard_symtab guard { *this }; 1924 1949 auto new_node = p.second->accept( *this ); 1925 if (new_node != p.second) mutated = false;1950 if (new_node != p.second) mutated = true; 1926 1951 new_map.insert({ p.first, new_node }); 1927 1952 } -
src/AST/Pass.proto.hpp
r057298e r7030dab 263 263 template<typename pass_t> 264 264 static inline void leave( pass_t &, long ) {} 265 } ;266 267 // Finally certain pass desire an up to date symbol table automatically265 } // namespace scope 266 267 // Certain passes desire an up to date symbol table automatically 268 268 // detect the presence of a member name `symtab` and call all the members appropriately 269 269 namespace symtab { 270 270 // Some simple scoping rules 271 271 template<typename pass_t> 272 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab .enterScope(), void() ) {272 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab, void() ) { 273 273 pass.symtab.enterScope(); 274 274 } … … 278 278 279 279 template<typename pass_t> 280 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab .leaveScope(), void() ) {280 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab, void() ) { 281 281 pass.symtab.leaveScope(); 282 282 } … … 311 311 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 312 312 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 313 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Node* );313 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 314 314 315 315 // A few extra functions have more complicated behaviour, they are hand written … … 356 356 #undef SYMTAB_FUNC1 357 357 #undef SYMTAB_FUNC2 358 }; 359 }; 360 }; 358 } // namespace symtab 359 360 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 361 // Detect the presence of a member name `subs` and call all members appropriately 362 namespace forall { 363 // Some simple scoping rules 364 template<typename pass_t> 365 static inline auto enter( pass_t & pass, int, const ast::ParameterizedType * type ) 366 -> decltype( pass.subs, void() ) { 367 if ( ! type->forall.empty() ) pass.subs.beginScope(); 368 } 369 370 template<typename pass_t> 371 static inline auto enter( pass_t &, long, const ast::ParameterizedType * ) {} 372 373 template<typename pass_t> 374 static inline auto leave( pass_t & pass, int, const ast::ParameterizedType * type ) 375 -> decltype( pass.subs, void() ) { 376 if ( ! type->forall.empty() ) { pass.subs.endScope(); } 377 } 378 379 template<typename pass_t> 380 static inline auto leave( pass_t &, long, const ast::ParameterizedType * ) {} 381 382 // Get the substitution table, if present 383 template<typename pass_t> 384 static inline auto subs( pass_t & pass, int ) -> decltype( &pass.subs ) { 385 return &pass.subs; 386 } 387 388 template<typename pass_t> 389 static inline ast::ForallSubstitutionTable * subs( pass_t &, long ) { return nullptr; } 390 391 // Replaces a TypeInstType's base TypeDecl according to the table 392 template<typename pass_t> 393 static inline auto replace( pass_t & pass, int, const ast::TypeInstType *& inst ) 394 -> decltype( pass.subs, void() ) { 395 inst = ast::mutate_field( 396 inst, &ast::TypeInstType::base, pass.subs.replace( inst->base ) ); 397 } 398 399 template<typename pass_t> 400 static inline auto replace( pass_t &, long, const ast::TypeInstType *& ) {} 401 402 } // namespace forall 403 } // namespace __pass 404 } // namespace ast -
src/AST/Stmt.hpp
r057298e r7030dab 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
r057298e r7030dab 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.pass( 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.pass( o.returns ); // apply to return and parameter types 110 params = sub.pass( 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.pass( 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" ); … … 118 150 // --- StructInstType 119 151 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 ) {}152 StructInstType::StructInstType( 153 const StructDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 154 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 123 155 124 156 bool StructInstType::isComplete() const { return base ? base->body : false; } … … 126 158 // --- UnionInstType 127 159 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 ) {}160 UnionInstType::UnionInstType( 161 const UnionDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 162 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 131 163 132 164 bool UnionInstType::isComplete() const { return base ? base->body : false; } … … 134 166 // --- EnumInstType 135 167 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 ) {}168 EnumInstType::EnumInstType( 169 const EnumDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 170 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 139 171 140 172 bool EnumInstType::isComplete() const { return base ? base->body : false; } … … 142 174 // --- TraitInstType 143 175 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 ) {}176 TraitInstType::TraitInstType( 177 const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 178 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 147 179 148 180 // --- TypeInstType 181 182 TypeInstType::TypeInstType( const TypeInstType & o ) 183 : ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) { 184 Pass< ForallSubstitutor > sub; 185 initWithSub( o, sub ); // initialize substitution 186 base = sub.pass( o.base ); // apply to base type 187 } 149 188 150 189 void TypeInstType::set_base( const TypeDecl * b ) { … … 158 197 159 198 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q ) 160 : Type( q ), types( std::move(ts) ), members() {199 : Type( q ), types( move(ts) ), members() { 161 200 // This constructor is awkward. `TupleType` needs to contain objects so that members can be 162 201 // named, but members without initializer nodes end up getting constructors, which breaks -
src/AST/Type.hpp
r057298e r7030dab 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 … … 338 359 readonly<StructDecl> base; 339 360 340 StructInstType( const std::string& n, CV::Qualifiers q = {},341 std::vector<ptr<Attribute>> && as = {} )361 StructInstType( 362 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 342 363 : ReferenceToType( n, q, std::move(as) ), base() {} 343 StructInstType( const StructDecl * b, CV::Qualifiers q = {}, 344 std::vector<ptr<Attribute>> && as = {} ); 364 365 StructInstType( 366 const StructDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 345 367 346 368 bool isComplete() const override; … … 359 381 readonly<UnionDecl> base; 360 382 361 UnionInstType( const std::string& n, CV::Qualifiers q = {},362 std::vector<ptr<Attribute>> && as = {} )383 UnionInstType( 384 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 363 385 : ReferenceToType( n, q, std::move(as) ), base() {} 364 UnionInstType( const UnionDecl * b, CV::Qualifiers q = {}, 365 std::vector<ptr<Attribute>> && as = {} ); 386 387 UnionInstType( 388 const UnionDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 366 389 367 390 bool isComplete() const override; … … 380 403 readonly<EnumDecl> base; 381 404 382 EnumInstType( const std::string& n, CV::Qualifiers q = {},383 std::vector<ptr<Attribute>> && as = {} )405 EnumInstType( 406 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 384 407 : ReferenceToType( n, q, std::move(as) ), base() {} 385 EnumInstType( const EnumDecl * b, CV::Qualifiers q = {}, 386 std::vector<ptr<Attribute>> && as = {} ); 408 409 EnumInstType( 410 const EnumDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 387 411 388 412 bool isComplete() const override; … … 401 425 readonly<TraitDecl> base; 402 426 403 TraitInstType( const std::string& n, CV::Qualifiers q = {},404 std::vector<ptr<Attribute>> && as = {} )427 TraitInstType( 428 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 405 429 : ReferenceToType( n, q, std::move(as) ), base() {} 406 TraitInstType( const TraitDecl * b, CV::Qualifiers q = {}, 407 std::vector<ptr<Attribute>> && as = {} ); 430 431 TraitInstType( 432 const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 408 433 409 434 // not meaningful for TraitInstType … … 424 449 TypeDecl::Kind kind; 425 450 426 TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 451 TypeInstType( 452 const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 427 453 std::vector<ptr<Attribute>> && as = {} ) 428 454 : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {} … … 431 457 : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {} 432 458 459 TypeInstType( const TypeInstType & o ); 460 433 461 /// sets `base`, updating `kind` correctly 434 462 void set_base( const TypeDecl * ); -
src/AST/TypeEnvironment.hpp
r057298e r7030dab 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
r057298e r7030dab 92 92 namespace { 93 93 struct EnvTrimmer { 94 ptr<TypeSubstitution>env;94 const TypeSubstitution * env; 95 95 TypeSubstitution * newEnv; 96 96 EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} … … 108 108 if ( env ) { 109 109 TypeSubstitution * newEnv = new TypeSubstitution(); 110 #if TIME_TO_CONVERT_PASSES111 110 Pass<EnvTrimmer> trimmer( env, newEnv ); 112 111 expr->accept( trimmer ); 113 #else114 (void)expr;115 (void)env;116 #endif117 112 return newEnv; 118 113 } … … 121 116 122 117 void TypeSubstitution::normalize() { 123 #if TIME_TO_CONVERT_PASSES 124 PassVisitor<Substituter> sub( *this, true ); 118 Pass<Substituter> sub( *this, true ); 125 119 do { 126 120 sub.pass.subCount = 0; 127 121 sub.pass.freeOnly = true; 128 122 for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) { 129 i->second = i->second->accept Mutator( sub );123 i->second = i->second->accept( sub ); 130 124 } 131 125 } while ( sub.pass.subCount ); 132 #endif 133 } 134 135 #if TIME_TO_CONVERT_PASSES 136 137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) { 126 } 127 128 const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) { 138 129 BoundVarsType::const_iterator bound = boundVars.find( inst->name ); 139 130 if ( bound != boundVars.end() ) return inst; … … 146 137 // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here. 147 138 // TODO: investigate preventing type variables from being bound to themselves in the first place. 148 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {139 if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) { 149 140 if ( inst->name == replacement->name ) { 150 141 return inst; … … 153 144 // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl; 154 145 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 ) { 146 ptr<Type> newType = i->second; // force clone if needed 147 add_qualifiers( newType, inst->qualifiers ); 148 // Note: need to recursively apply substitution to the new type because normalize does not 149 // substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 150 newType = newType->accept( *visitor ); 151 return newType.release(); 152 } // if 153 } 154 155 const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) { 164 156 VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name ); 165 157 if ( i == sub.varEnv.end() ) { … … 167 159 } else { 168 160 subCount++; 169 delete nameExpr; 170 return i->second->clone(); 171 } // if 172 } 173 174 void TypeSubstitution::Substituter::premutate( Type * type ) { 161 return i->second; 162 } // if 163 } 164 165 void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) { 175 166 GuardValue( boundVars ); 176 167 // bind type variables from forall-qualifiers 177 168 if ( freeOnly ) { 178 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {179 boundVars.insert( (*tyvar)->name );169 for ( const TypeDecl * tyvar : ptype->forall ) { 170 boundVars.insert( tyvar->name ); 180 171 } // for 181 172 } // if 182 173 } 183 174 184 template< typename TypeClass > 185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) { 175 void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) { 186 176 GuardValue( boundVars ); 187 177 // bind type variables from forall-qualifiers 188 178 if ( freeOnly ) { 189 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {190 boundVars.insert( (*tyvar)->name );179 for ( const TypeDecl * tyvar : type->forall ) { 180 boundVars.insert( tyvar->name ); 191 181 } // for 192 182 // 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 ) { 183 if ( auto decl = type->aggr() ) { 184 if ( ! type->params.empty() ) { 185 for ( const TypeDecl * tyvar : decl->params ) { 186 boundVars.insert( tyvar->name ); 187 } // for 188 } // if 189 } 190 } // if 191 } 192 193 void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) { 203 194 handleAggregateType( aggregateUseType ); 204 195 } 205 196 206 void TypeSubstitution::Substituter::pre mutate(UnionInstType *aggregateUseType ) {197 void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) { 207 198 handleAggregateType( aggregateUseType ); 208 199 } 209 210 #endif211 200 212 201 } // namespace ast -
src/AST/TypeSubstitution.hpp
r057298e r7030dab 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 int count; 50 }; 51 52 template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const; 53 template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const; 48 54 49 55 template< typename node_t, enum Node::ref_type ref_t > 50 56 int apply( ptr_base< node_t, ref_t > & input ) const { 51 57 const node_t * p = input.get(); 52 intret = apply(p);53 input = p;54 return ret ;58 auto ret = apply(p); 59 input = ret.node; 60 return ret.count; 55 61 } 56 62 … … 58 64 int applyFree( ptr_base< node_t, ref_t > & input ) const { 59 65 const node_t * p = input.get(); 60 intret = applyFree(p);61 input = p;62 return ret ;66 auto ret = applyFree(p); 67 input = ret.node; 68 return ret.count; 63 69 } 64 70 … … 155 161 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {} 156 162 157 #if TIME_TO_CONVERT_PASSES 158 159 Type * postmutate( TypeInstType * aggregateUseType ); 160 Expression * postmutate( NameExpr * nameExpr ); 163 const Type * postvisit( const TypeInstType * aggregateUseType ); 164 const Expr * postvisit( const NameExpr * nameExpr ); 161 165 162 166 /// Records type variable bindings from forall-statements 163 void pre mutate(Type * type );167 void previsit( const ParameterizedType * type ); 164 168 /// 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 169 void handleAggregateType( const ReferenceToType * type ); 170 171 void previsit( const StructInstType * aggregateUseType ); 172 void previsit( const UnionInstType * aggregateUseType ); 171 173 172 174 const TypeSubstitution & sub; … … 179 181 180 182 template< typename SynTreeClass > 181 int TypeSubstitution::apply( const SynTreeClass *&input ) const {183 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const { 182 184 assert( input ); 183 185 Pass<Substituter> sub( *this, false ); 184 186 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; 187 return { input, sub.pass.subCount }; 189 188 } 190 189 191 190 template< typename SynTreeClass > 192 int TypeSubstitution::applyFree( const SynTreeClass *&input ) const {191 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const { 193 192 assert( input ); 194 193 Pass<Substituter> sub( *this, true ); 195 194 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; 195 return { input, sub.pass.subCount }; 200 196 } 201 197 -
src/AST/module.mk
r057298e r7030dab 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/Common/ScopedMap.h
r057298e r7030dab 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/Makefile.in
r057298e r7030dab 169 169 AST/Convert.$(OBJEXT) AST/Decl.$(OBJEXT) \ 170 170 AST/DeclReplacer.$(OBJEXT) AST/Expr.$(OBJEXT) \ 171 AST/ForallSubstitutionTable.$(OBJEXT) \ 171 172 AST/GenericSubstitution.$(OBJEXT) AST/Init.$(OBJEXT) \ 172 173 AST/LinkageSpec.$(OBJEXT) AST/Node.$(OBJEXT) \ … … 589 590 AST/DeclReplacer.cpp \ 590 591 AST/Expr.cpp \ 592 AST/ForallSubstitutionTable.cpp \ 591 593 AST/GenericSubstitution.cpp \ 592 594 AST/Init.cpp \ … … 765 767 AST/$(DEPDIR)/$(am__dirstamp) 766 768 AST/Expr.$(OBJEXT): AST/$(am__dirstamp) AST/$(DEPDIR)/$(am__dirstamp) 769 AST/ForallSubstitutionTable.$(OBJEXT): AST/$(am__dirstamp) \ 770 AST/$(DEPDIR)/$(am__dirstamp) 767 771 AST/GenericSubstitution.$(OBJEXT): AST/$(am__dirstamp) \ 768 772 AST/$(DEPDIR)/$(am__dirstamp) … … 1218 1222 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/DeclReplacer.Po@am__quote@ 1219 1223 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Expr.Po@am__quote@ 1224 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/ForallSubstitutionTable.Po@am__quote@ 1220 1225 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/GenericSubstitution.Po@am__quote@ 1221 1226 @AMDEP_TRUE@@am__include@ @am__quote@AST/$(DEPDIR)/Init.Po@am__quote@ -
src/ResolvExpr/AdjustExprType.cc
r057298e r7030dab 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
r057298e r7030dab 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
r057298e r7030dab 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: 597 598 CandidateFinder & selfFinder; 598 const ast::SymbolTable & symtab;599 599 CandidateList & candidates; 600 600 const ast::TypeEnvironment & tenv; 601 601 ast::ptr< ast::Type > & targetType; 602 602 603 enum Errors { 604 NotFound, 605 NoMatch, 606 ArgsToFew, 607 ArgsToMany, 608 RetsToFew, 609 RetsToMany, 610 NoReason 611 }; 612 613 struct { 614 Errors code = NotFound; 615 } reason; 616 603 617 Finder( CandidateFinder & f ) 604 : s elfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),618 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 605 619 targetType( f.targetType ) {} 606 620 607 621 void previsit( const ast::Node * ) { visit_children = false; } 608 622 … … 611 625 void addCandidate( Args &&... args ) { 612 626 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 627 reason.code = NoReason; 613 628 } 614 629 … … 639 654 640 655 /// Completes a function candidate with arguments located 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 656 void validateFunctionCandidate( 657 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 658 CandidateList & out 644 659 ) { 645 ast::ApplicationExpr * appExpr = 660 ast::ApplicationExpr * appExpr = 646 661 new ast::ApplicationExpr{ func->expr->location, func->expr }; 647 662 // sum cost and accumulate arguments … … 657 672 appExpr->args = move( vargs ); 658 673 // build and validate new candidate 659 auto newCand = 674 auto newCand = 660 675 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 661 676 PRINT( … … 669 684 /// Builds a list of candidates for a function, storing them in out 670 685 void makeFunctionCandidates( 671 const CandidateRef & func, const ast::FunctionType * funcType, 686 const CandidateRef & func, const ast::FunctionType * funcType, 672 687 const ExplodedArgs_new & args, CandidateList & out 673 688 ) { … … 676 691 ast::TypeEnvironment funcEnv{ func->env }; 677 692 makeUnifiableVars( funcType, funcOpen, funcNeed ); 678 // add all type variables as open variables now so that those not used in the parameter679 // list are still considered open693 // add all type variables as open variables now so that those not used in the 694 // parameter list are still considered open 680 695 funcEnv.add( funcType->forall ); 681 696 … … 683 698 // attempt to narrow based on expected target type 684 699 const ast::Type * returnType = funcType->returns.front()->get_type(); 685 if ( ! unify( 686 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 700 if ( ! unify( 701 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 687 702 ) { 688 703 // unification failed, do not pursue this candidate … … 698 713 for ( const ast::DeclWithType * param : funcType->params ) { 699 714 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param ); 700 // Try adding the arguments corresponding to the current parameter to the existing 715 // Try adding the arguments corresponding to the current parameter to the existing 701 716 // matches 702 if ( ! instantiateArgument( 717 if ( ! instantiateArgument( 703 718 obj->type, obj->init, args, results, genStart, symtab ) ) return; 704 719 } … … 750 765 if ( expl.exprs.empty() ) { 751 766 results.emplace_back( 752 results[i], move( env ), copy( results[i].need ), 753 copy( results[i].have ), move( open ), nextArg + 1, 767 results[i], move( env ), copy( results[i].need ), 768 copy( results[i].have ), move( open ), nextArg + 1, 754 769 expl.cost ); 755 770 … … 760 775 results.emplace_back( 761 776 i, expl.exprs.front(), move( env ), copy( results[i].need ), 762 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 777 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 763 778 expl.exprs.size() == 1 ? 0 : 1, j ); 764 779 } … … 780 795 /// Adds implicit struct-conversions to the alternative list 781 796 void addAnonConversions( const CandidateRef & cand ) { 782 // adds anonymous member interpretations whenever an aggregate value type is seen. 783 // it's okay for the aggregate expression to have reference type -- cast it to the 797 // adds anonymous member interpretations whenever an aggregate value type is seen. 798 // it's okay for the aggregate expression to have reference type -- cast it to the 784 799 // base type to treat the aggregate as the referenced value 785 800 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 786 801 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 787 802 cand->env.apply( aggrType ); 788 803 789 804 if ( aggrType.as< ast::ReferenceType >() ) { 790 805 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; … … 799 814 800 815 /// Adds aggregate member interpretations 801 void addAggMembers( 802 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 803 const Candidate & cand, const Cost & addedCost, const std::string & name 816 void addAggMembers( 817 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 818 const Candidate & cand, const Cost & addedCost, const std::string & name 804 819 ) { 805 820 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 806 821 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 807 CandidateRef newCand = std::make_shared<Candidate>( 822 CandidateRef newCand = std::make_shared<Candidate>( 808 823 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 809 // add anonymous member interpretations whenever an aggregate value type is seen 824 // add anonymous member interpretations whenever an aggregate value type is seen 810 825 // as a member expression 811 826 addAnonConversions( newCand ); … … 815 830 816 831 /// Adds tuple member interpretations 817 void addTupleMembers( 818 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 819 const Cost & addedCost, const ast::Expr * member 832 void addTupleMembers( 833 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 834 const Cost & addedCost, const ast::Expr * member 820 835 ) { 821 836 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 822 // get the value of the constant expression as an int, must be between 0 and the 837 // get the value of the constant expression as an int, must be between 0 and the 823 838 // length of the tuple to have meaning 824 839 long long val = constantExpr->intValue(); 825 840 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 826 841 addCandidate( 827 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 842 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 828 843 addedCost ); 829 844 } … … 837 852 if ( funcFinder.candidates.empty() ) return; 838 853 839 std::vector< CandidateFinder > argCandidates = 854 reason.code = NoMatch; 855 856 std::vector< CandidateFinder > argCandidates = 840 857 selfFinder.findSubExprs( untypedExpr->args ); 841 858 842 859 // take care of possible tuple assignments 843 860 // if not tuple assignment, handled as normal function call … … 877 894 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 878 895 CandidateRef newFunc{ new Candidate{ *func } }; 879 newFunc->expr = 896 newFunc->expr = 880 897 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 881 898 makeFunctionCandidates( newFunc, function, argExpansions, found ); 882 899 } 883 } else if ( 884 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 900 } else if ( 901 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 885 902 ) { 886 903 if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) { 887 904 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 888 905 CandidateRef newFunc{ new Candidate{ *func } }; 889 newFunc->expr = 906 newFunc->expr = 890 907 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 891 908 makeFunctionCandidates( newFunc, function, argExpansions, found ); … … 901 918 std::vector< ExplodedArg > funcE; 902 919 funcE.reserve( funcFinder.candidates.size() ); 903 for ( const CandidateRef & func : funcFinder ) { 920 for ( const CandidateRef & func : funcFinder ) { 904 921 funcE.emplace_back( *func, symtab ); 905 922 } … … 913 930 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 914 931 CandidateRef newOp{ new Candidate{ *op} }; 915 newOp->expr = 932 newOp->expr = 916 933 referenceToRvalueConversion( newOp->expr, newOp->cost ); 917 934 makeFunctionCandidates( newOp, function, argExpansions, found ); … … 922 939 } 923 940 924 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 941 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 925 942 // candidates 926 943 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } … … 934 951 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 935 952 auto function = pointer->base.strict_as< ast::FunctionType >(); 936 953 937 954 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 938 955 std::cerr << "parameters are:" << std::endl; … … 957 974 promoteCvtCost( winners ); 958 975 959 // function may return a struct/union value, in which case we need to add candidates 960 // for implicit conversions to each of the anonymous members, which must happen after 976 // function may return a struct/union value, in which case we need to add candidates 977 // for implicit conversions to each of the anonymous members, which must happen after 961 978 // `findMinCost`, since anon conversions are never the cheapest 962 979 for ( const CandidateRef & c : winners ) { … … 966 983 967 984 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 968 // If resolution is unsuccessful with a target type, try again without, since it 985 // If resolution is unsuccessful with a target type, try again without, since it 969 986 // will sometimes succeed when it wouldn't with a target type binding. 970 987 // For example: … … 983 1000 /// true if expression is an lvalue 984 1001 static bool isLvalue( const ast::Expr * x ) { 985 return x->result && ( x-> result->is_lvalue() || x->result.as< ast::ReferenceType >() );1002 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 986 1003 } 987 1004 … … 989 1006 CandidateFinder finder{ symtab, tenv }; 990 1007 finder.find( addressExpr->arg ); 1008 1009 if( finder.candidates.empty() ) return; 1010 1011 reason.code = NoMatch; 1012 991 1013 for ( CandidateRef & r : finder.candidates ) { 992 1014 if ( ! isLvalue( r->expr ) ) continue; … … 1009 1031 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1010 1032 1033 if( !finder.candidates.empty() ) reason.code = NoMatch; 1034 1011 1035 CandidateList matches; 1012 1036 for ( CandidateRef & cand : finder.candidates ) { … … 1016 1040 cand->env.extractOpenVars( open ); 1017 1041 1018 // It is possible that a cast can throw away some values in a multiply-valued 1019 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1020 // subexpression results that are cast directly. The candidate is invalid if it 1042 // It is possible that a cast can throw away some values in a multiply-valued 1043 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1044 // subexpression results that are cast directly. The candidate is invalid if it 1021 1045 // has fewer results than there are types to cast to. 1022 1046 int discardedValues = cand->expr->result->size() - toType->size(); … … 1025 1049 // unification run for side-effects 1026 1050 unify( toType, cand->expr->result, cand->env, need, have, open, symtab ); 1027 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env ); 1051 Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1052 symtab, cand->env ); 1028 1053 PRINT( 1029 1054 std::cerr << "working on cast with result: " << toType << std::endl; … … 1037 1062 // count one safe conversion for each value that is thrown away 1038 1063 thisCost.incSafe( discardedValues ); 1039 CandidateRef newCand = std::make_shared<Candidate>( 1040 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1041 copy( cand->env ), move( open ), move( need ), cand->cost, 1064 CandidateRef newCand = std::make_shared<Candidate>( 1065 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1066 copy( cand->env ), move( open ), move( need ), cand->cost, 1042 1067 cand->cost + thisCost ); 1043 1068 inferParameters( newCand, matches ); … … 1057 1082 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1058 1083 for ( CandidateRef & r : finder.candidates ) { 1059 addCandidate( 1060 *r, 1084 addCandidate( 1085 *r, 1061 1086 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1062 1087 } … … 1067 1092 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1068 1093 for ( CandidateRef & agg : aggFinder.candidates ) { 1069 // it's okay for the aggregate expression to have reference type -- cast it to the 1094 // it's okay for the aggregate expression to have reference type -- cast it to the 1070 1095 // base type to treat the aggregate as the referenced value 1071 1096 Cost addedCost = Cost::zero; … … 1074 1099 // find member of the given type 1075 1100 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1076 addAggMembers( 1101 addAggMembers( 1077 1102 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1078 1103 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1079 addAggMembers( 1104 addAggMembers( 1080 1105 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1081 1106 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1092 1117 std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name ); 1093 1118 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1119 if( declList.empty() ) return; 1120 1121 reason.code = NoMatch; 1122 1094 1123 for ( auto & data : declList ) { 1095 1124 Cost cost = Cost::zero; … … 1097 1126 1098 1127 CandidateRef newCand = std::make_shared<Candidate>( 1099 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1128 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1100 1129 cost ); 1101 1130 PRINT( … … 1107 1136 std::cerr << std::endl; 1108 1137 ) 1109 newCand->expr = ast::mutate_field( 1110 newCand->expr.get(), &ast::Expr::result, 1138 newCand->expr = ast::mutate_field( 1139 newCand->expr.get(), &ast::Expr::result, 1111 1140 renameTyVars( newCand->expr->result ) ); 1112 // add anonymous member interpretations whenever an aggregate value type is seen 1141 // add anonymous member interpretations whenever an aggregate value type is seen 1113 1142 // as a name expression 1114 1143 addAnonConversions( newCand ); … … 1120 1149 // not sufficient to just pass `variableExpr` here, type might have changed since 1121 1150 // creation 1122 addCandidate( 1151 addCandidate( 1123 1152 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1124 1153 } … … 1130 1159 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1131 1160 if ( sizeofExpr->type ) { 1132 addCandidate( 1133 new ast::SizeofExpr{ 1134 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1161 addCandidate( 1162 new ast::SizeofExpr{ 1163 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1135 1164 tenv ); 1136 1165 } else { … … 1141 1170 CandidateList winners = findMinCost( finder.candidates ); 1142 1171 if ( winners.size() != 1 ) { 1143 SemanticError( 1172 SemanticError( 1144 1173 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1145 1174 } … … 1154 1183 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1155 1184 if ( alignofExpr->type ) { 1156 addCandidate( 1157 new ast::AlignofExpr{ 1158 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1185 addCandidate( 1186 new ast::AlignofExpr{ 1187 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1159 1188 tenv ); 1160 1189 } else { … … 1165 1194 CandidateList winners = findMinCost( finder.candidates ); 1166 1195 if ( winners.size() != 1 ) { 1167 SemanticError( 1196 SemanticError( 1168 1197 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1169 1198 } … … 1172 1201 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1173 1202 choice->cost = Cost::zero; 1174 addCandidate( 1203 addCandidate( 1175 1204 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1176 1205 } … … 1185 1214 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1186 1215 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1187 addCandidate( 1216 addCandidate( 1188 1217 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1189 1218 } … … 1206 1235 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1207 1236 if ( finder2.candidates.empty() ) return; 1237 1238 reason.code = NoMatch; 1208 1239 1209 1240 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1218 1249 1219 1250 addCandidate( 1220 new ast::LogicalExpr{ 1251 new ast::LogicalExpr{ 1221 1252 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1222 1253 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1240 1271 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1241 1272 if ( finder3.candidates.empty() ) return; 1273 1274 reason.code = NoMatch; 1242 1275 1243 1276 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1256 1289 ast::AssertionSet have; 1257 1290 1258 // unify true and false results, then infer parameters to produce new 1291 // unify true and false results, then infer parameters to produce new 1259 1292 // candidates 1260 1293 ast::ptr< ast::Type > common; 1261 if ( 1262 unify( 1263 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1264 common ) 1294 if ( 1295 unify( 1296 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1297 common ) 1265 1298 ) { 1266 1299 // generate typed expression 1267 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1300 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1268 1301 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1269 1302 newExpr->result = common ? common : r2->expr->result; 1270 1303 // convert both options to result type 1271 1304 Cost cost = r1->cost + r2->cost + r3->cost; 1272 newExpr->arg2 = computeExpressionConversionCost( 1305 newExpr->arg2 = computeExpressionConversionCost( 1273 1306 newExpr->arg2, newExpr->result, symtab, env, cost ); 1274 1307 newExpr->arg3 = computeExpressionConversionCost( … … 1287 1320 ast::TypeEnvironment env{ tenv }; 1288 1321 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1289 1322 1290 1323 CandidateFinder finder2{ symtab, env }; 1291 1324 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1317 1350 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1318 1351 if ( finder2.candidates.empty() ) return; 1352 1353 reason.code = NoMatch; 1319 1354 1320 1355 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1330 1365 1331 1366 ast::ptr< ast::Type > common; 1332 if ( 1333 unify( 1334 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1335 common ) 1367 if ( 1368 unify( 1369 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1370 common ) 1336 1371 ) { 1337 1372 // generate new expression 1338 ast::RangeExpr * newExpr = 1373 ast::RangeExpr * newExpr = 1339 1374 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1340 1375 newExpr->result = common ? common : r1->expr->result; 1341 1376 // add candidate 1342 1377 CandidateRef newCand = std::make_shared<Candidate>( 1343 newExpr, move( env ), move( open ), move( need ), 1378 newExpr, move( env ), move( open ), move( need ), 1344 1379 r1->cost + r2->cost ); 1345 1380 inferParameters( newCand, candidates ); … … 1350 1385 1351 1386 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1352 std::vector< CandidateFinder > subCandidates = 1387 std::vector< CandidateFinder > subCandidates = 1353 1388 selfFinder.findSubExprs( tupleExpr->exprs ); 1354 1389 std::vector< CandidateList > possibilities; … … 1370 1405 1371 1406 addCandidate( 1372 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1407 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1373 1408 move( env ), move( open ), move( need ), sumCost( subs ) ); 1374 1409 } … … 1412 1447 toType = SymTab::validateType( initExpr->location, toType, symtab ); 1413 1448 toType = adjustExprType( toType, tenv, symtab ); 1414 // The call to find must occur inside this loop, otherwise polymorphic return 1415 // types are not bound to the initialization type, since return type variables are 1416 // only open for the duration of resolving the UntypedExpr. 1449 // The call to find must occur inside this loop, otherwise polymorphic return 1450 // types are not bound to the initialization type, since return type variables are 1451 // only open for the duration of resolving the UntypedExpr. 1417 1452 CandidateFinder finder{ symtab, tenv, toType }; 1418 1453 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1419 1454 for ( CandidateRef & cand : finder.candidates ) { 1455 if(reason.code == NotFound) reason.code = NoMatch; 1456 1420 1457 ast::TypeEnvironment env{ cand->env }; 1421 1458 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; … … 1426 1463 ) 1427 1464 1428 // It is possible that a cast can throw away some values in a multiply-valued 1429 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1430 // the subexpression results that are cast directly. The candidate is invalid 1465 // It is possible that a cast can throw away some values in a multiply-valued 1466 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1467 // the subexpression results that are cast directly. The candidate is invalid 1431 1468 // if it has fewer results than there are types to cast to. 1432 1469 int discardedValues = cand->expr->result->size() - toType->size(); … … 1435 1472 // unification run for side-effects 1436 1473 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1437 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1438 1474 Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1475 symtab, env ); 1476 1439 1477 if ( thisCost != Cost::infinity ) { 1440 1478 // count one safe conversion for each value that is thrown away 1441 1479 thisCost.incSafe( discardedValues ); 1442 CandidateRef newCand = std::make_shared<Candidate>( 1443 new ast::InitExpr{ 1444 initExpr->location, restructureCast( cand->expr, toType ), 1445 initAlt.designation }, 1480 CandidateRef newCand = std::make_shared<Candidate>( 1481 new ast::InitExpr{ 1482 initExpr->location, restructureCast( cand->expr, toType ), 1483 initAlt.designation }, 1446 1484 copy( cand->env ), move( open ), move( need ), cand->cost, thisCost ); 1447 1485 inferParameters( newCand, matches ); … … 1469 1507 }; 1470 1508 1471 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1509 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1472 1510 /// return type. Skips ambiguous candidates. 1473 1511 CandidateList pruneCandidates( CandidateList & candidates ) { … … 1486 1524 { 1487 1525 ast::ptr< ast::Type > newType = candidate->expr->result; 1526 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1488 1527 candidate->env.apply( newType ); 1489 1528 mangleName = Mangle::mangle( newType ); … … 1494 1533 if ( candidate->cost < found->second.candidate->cost ) { 1495 1534 PRINT( 1496 std::cerr << "cost " << candidate->cost << " beats " 1535 std::cerr << "cost " << candidate->cost << " beats " 1497 1536 << found->second.candidate->cost << std::endl; 1498 1537 ) … … 1500 1539 found->second = PruneStruct{ candidate }; 1501 1540 } else if ( candidate->cost == found->second.candidate->cost ) { 1502 // if one of the candidates contains a deleted identifier, can pick the other, 1503 // since deleted expressions should not be ambiguous if there is another option 1541 // if one of the candidates contains a deleted identifier, can pick the other, 1542 // since deleted expressions should not be ambiguous if there is another option 1504 1543 // that is at least as good 1505 1544 if ( findDeletedExpr( candidate->expr ) ) { … … 1515 1554 } else { 1516 1555 PRINT( 1517 std::cerr << "cost " << candidate->cost << " loses to " 1556 std::cerr << "cost " << candidate->cost << " loses to " 1518 1557 << found->second.candidate->cost << std::endl; 1519 1558 ) … … 1530 1569 1531 1570 CandidateRef cand = target.second.candidate; 1532 1571 1533 1572 ast::ptr< ast::Type > newResult = cand->expr->result; 1534 1573 cand->env.applyFree( newResult ); 1535 1574 cand->expr = ast::mutate_field( 1536 1575 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1537 1576 1538 1577 out.emplace_back( cand ); 1539 1578 } … … 1549 1588 1550 1589 if ( mode.failFast && candidates.empty() ) { 1551 SemanticError( expr, "No reasonable alternatives for expression " ); 1590 switch(finder.pass.reason.code) { 1591 case Finder::NotFound: 1592 { SemanticError( expr, "No alternatives for expression " ); break; } 1593 case Finder::NoMatch: 1594 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1595 case Finder::ArgsToFew: 1596 case Finder::ArgsToMany: 1597 case Finder::RetsToFew: 1598 case Finder::RetsToMany: 1599 case Finder::NoReason: 1600 default: 1601 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1602 } 1552 1603 } 1553 1604 … … 1558 1609 std::vector< std::string > errors; 1559 1610 for ( CandidateRef & candidate : candidates ) { 1560 satisfyAssertions( candidate, symtab, satisfied, errors );1611 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1561 1612 } 1562 1613 … … 1583 1634 1584 1635 CandidateList pruned = pruneCandidates( candidates ); 1585 1636 1586 1637 if ( mode.failFast && pruned.empty() ) { 1587 1638 std::ostringstream stream; … … 1602 1653 ) 1603 1654 PRINT( 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1655 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1605 1656 << std::endl; 1606 1657 ) 1607 1658 } 1608 1659 1609 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1660 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1610 1661 // adjusted 1611 1662 if ( mode.adjust ) { 1612 1663 for ( CandidateRef & r : candidates ) { 1613 r->expr = ast::mutate_field( 1614 r->expr.get(), &ast::Expr::result, 1615 adjustExprType( r->expr->result, r->env, symtab) );1664 r->expr = ast::mutate_field( 1665 r->expr.get(), &ast::Expr::result, 1666 adjustExprType( r->expr->result, r->env, localSyms ) ); 1616 1667 } 1617 1668 } … … 1625 1676 } 1626 1677 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1678 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1679 const std::vector< ast::ptr< ast::Expr > > & xs 1629 1680 ) { 1630 1681 std::vector< CandidateFinder > out; 1631 1682 1632 1683 for ( const auto & x : xs ) { 1633 out.emplace_back( symtab, env );1684 out.emplace_back( localSyms, env ); 1634 1685 out.back().find( x, ResolvMode::withAdjustment() ); 1635 1686 1636 1687 PRINT( 1637 1688 std::cerr << "findSubExprs" << std::endl; -
src/ResolvExpr/CandidateFinder.hpp
r057298e r7030dab 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 9:51:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 28 28 struct CandidateFinder { 29 29 CandidateList candidates; ///< List of candidate resolutions 30 const ast::SymbolTable & symtab; ///< Symbol table to lookup candidates30 const ast::SymbolTable & localSyms; ///< Symbol table to lookup candidates 31 31 const ast::TypeEnvironment & env; ///< Substitutions performed in this resolution 32 32 ast::ptr< ast::Type > targetType; ///< Target type for resolution 33 33 34 CandidateFinder( 35 const ast::SymbolTable & sym tab, const ast::TypeEnvironment & env,34 CandidateFinder( 35 const ast::SymbolTable & syms, const ast::TypeEnvironment & env, 36 36 const ast::Type * tt = nullptr ) 37 : candidates(), symtab( symtab), env( env ), targetType( tt ) {}37 : candidates(), localSyms( syms ), env( env ), targetType( tt ) {} 38 38 39 39 /// Fill candidates with feasible resolutions for `expr` … … 49 49 iterator begin() { return candidates.begin(); } 50 50 const_iterator begin() const { return candidates.begin(); } 51 51 52 52 iterator end() { return candidates.end(); } 53 53 const_iterator end() const { return candidates.end(); } … … 55 55 56 56 /// Computes conversion cost between two types 57 Cost computeConversionCost( 58 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,59 const ast:: TypeEnvironment & env );57 Cost computeConversionCost( 58 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 59 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 60 60 61 61 } // namespace ResolvExpr -
src/ResolvExpr/CastCost.cc
r057298e r7030dab 10 10 // Created On : Sun May 17 06:57:43 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:12:00 201913 // Update Count : 812 // Last Modified On : Tue Oct 4 15:00:00 2019 13 // Update Count : 9 14 14 // 15 15 … … 142 142 143 143 CastCost_new( 144 const ast::Type * dst, const ast::SymbolTable & symtab,144 const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 145 145 const ast::TypeEnvironment & env, CostCalculation costFunc ) 146 : ConversionCost_new( dst, s ymtab, env, costFunc ) {}146 : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {} 147 147 148 148 void postvisit( const ast::BasicType * basicType ) { … … 152 152 cost = Cost::unsafe; 153 153 } else { 154 cost = conversionCost( basicType, dst, s ymtab, env );154 cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env ); 155 155 } 156 156 } … … 183 183 } 184 184 }; 185 186 #warning For overload resolution between the two versions. 187 int localPtrsCastable(const ast::Type * t1, const ast::Type * t2, 188 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) { 189 return ptrsCastable( t1, t2, symtab, env ); 190 } 191 Cost localCastCost( 192 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 193 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 194 ) { return castCost( src, dst, srcIsLvalue, symtab, env ); } 185 195 } // anonymous namespace 186 196 197 198 187 199 Cost castCost( 188 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,189 const ast:: TypeEnvironment & env200 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 201 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 190 202 ) { 191 203 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { … … 193 205 // check cast cost against bound type, if present 194 206 if ( eqvClass->bound ) { 195 return castCost( src, eqvClass->bound, s ymtab, env );207 return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env ); 196 208 } else { 197 209 return Cost::infinity; … … 201 213 auto type = strict_dynamic_cast< const ast::TypeDecl * >( named ); 202 214 if ( type->base ) { 203 return castCost( src, type->base, s ymtab, env ) + Cost::safe;215 return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe; 204 216 } 205 217 } … … 224 236 #warning cast on ptrsCastable artifact of having two functions, remove when port done 225 237 return convertToReferenceCost( 226 src, refType, symtab, env, 227 ( int (*)( 228 const ast::Type *, const ast::Type *, const ast::SymbolTable &, 229 const ast::TypeEnvironment & ) 230 ) ptrsCastable ); 238 src, refType, srcIsLvalue, symtab, env, localPtrsCastable ); 231 239 } else { 232 240 #warning cast on castCost artifact of having two functions, remove when port done 233 ast::Pass< CastCost_new > converter{ 234 dst, symtab, env, 235 ( Cost (*)( 236 const ast::Type *, const ast::Type *, const ast::SymbolTable &, 237 const ast::TypeEnvironment & ) 238 ) castCost }; 241 ast::Pass< CastCost_new > converter( 242 dst, srcIsLvalue, symtab, env, localCastCost ); 239 243 src->accept( converter ); 240 244 return converter.pass.cost; -
src/ResolvExpr/CommonType.cc
r057298e r7030dab 939 939 ast::ptr< ast::Type > result; 940 940 const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >(); 941 const ast::ReferenceType * ref2 = type 1.as< ast::ReferenceType >();941 const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >(); 942 942 943 943 if ( depth1 > depth2 ) { -
src/ResolvExpr/ConversionCost.cc
r057298e r7030dab 10 10 // Created On : Sun May 17 07:06:19 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Aug 12 10:21:00 201913 // Update Count : 2 712 // Last Modified On : Fri Oct 4 14:45:00 2019 13 // Update Count : 28 14 14 // 15 15 … … 497 497 } 498 498 499 static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 500 const ast::SymbolTable &, const ast::TypeEnvironment & env ) {501 return ptrsAssignable( t1, t2, env );502 } 503 504 // TODO: This is used for overload resolution. It might be able to be dropped once the old system 505 // is removed. 506 static Cost localConversionCost( 507 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,508 const ast::TypeEnvironment & env509 ) { return conversionCost( src, dst, symtab, env );}499 namespace { 500 # warning For overload resolution between the two versions. 501 int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 502 const ast::SymbolTable &, const ast::TypeEnvironment & env ) { 503 return ptrsAssignable( t1, t2, env ); 504 } 505 Cost localConversionCost( 506 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 507 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 508 ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); } 509 } 510 510 511 511 Cost conversionCost( 512 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,513 const ast:: TypeEnvironment & env512 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 513 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 514 514 ) { 515 515 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 516 516 if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) { 517 517 if ( eqv->bound ) { 518 return conversionCost(src, eqv->bound, s ymtab, env );518 return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env ); 519 519 } else { 520 520 return Cost::infinity; … … 524 524 assertf( type, "Unexpected typedef." ); 525 525 if ( type->base ) { 526 return conversionCost( src, type->base, s ymtab, env ) + Cost::safe;526 return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe; 527 527 } 528 528 } … … 534 534 } else if ( const ast::ReferenceType * refType = 535 535 dynamic_cast< const ast::ReferenceType * >( dst ) ) { 536 return convertToReferenceCost( src, refType, s ymtab, env, localPtrsAssignable );536 return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable ); 537 537 } else { 538 ast::Pass<ConversionCost_new> converter( dst, s ymtab, env, localConversionCost );538 ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost ); 539 539 src->accept( converter ); 540 540 return converter.pass.cost; … … 542 542 } 543 543 544 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, 544 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 545 545 int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 546 NumCostCalculation func ) {546 PtrsCalculation func ) { 547 547 if ( 0 < diff ) { 548 548 Cost cost = convertToReferenceCost( 549 strict_dynamic_cast< const ast::ReferenceType * >( src )->base, 550 dst, (diff - 1), symtab, env, func );549 strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst, 550 srcIsLvalue, (diff - 1), symtab, env, func ); 551 551 cost.incReference(); 552 552 return cost; … … 554 554 Cost cost = convertToReferenceCost( 555 555 src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base, 556 (diff + 1), symtab, env, func );556 srcIsLvalue, (diff + 1), symtab, env, func ); 557 557 cost.incReference(); 558 558 return cost; … … 579 579 } 580 580 } else { 581 ast::Pass<ConversionCost_new> converter( dst, s ymtab, env, localConversionCost );581 ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost ); 582 582 src->accept( converter ); 583 583 return converter.pass.cost; … … 588 588 assert( dstAsRef ); 589 589 if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) { 590 if ( src ->is_lvalue()) {590 if ( srcIsLvalue ) { 591 591 if ( src->qualifiers == dstAsRef->base->qualifiers ) { 592 592 return Cost::reference; … … 607 607 608 608 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst, 609 610 NumCostCalculation func ) {609 bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 610 PtrsCalculation func ) { 611 611 int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth(); 612 return convertToReferenceCost( src, dst, s depth - ddepth, symtab, env, func );612 return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func ); 613 613 } 614 614 … … 667 667 assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) ); 668 668 669 cost = costCalc( refType->base, dst, s ymtab, env );669 cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env ); 670 670 if ( refType->base->qualifiers == dst->qualifiers ) { 671 671 cost.incReference(); … … 701 701 void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) { 702 702 (void)enumInstType; 703 static const ast::BasicType integer( ast::BasicType::SignedInt );704 cost = costCalc( &integer, dst, symtab, env );703 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) }; 704 cost = costCalc( integer, dst, srcIsLvalue, symtab, env ); 705 705 if ( cost < Cost::unsafe ) { 706 706 cost.incSafe(); … … 714 714 void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) { 715 715 if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) { 716 cost = costCalc( eqv->bound, dst, s ymtab, env );716 cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env ); 717 717 } else if ( const ast::TypeInstType * dstAsInst = 718 718 dynamic_cast< const ast::TypeInstType * >( dst ) ) { … … 724 724 assertf( type, "Unexpected typedef."); 725 725 if ( type->base ) { 726 cost = costCalc( type->base, dst, s ymtab, env ) + Cost::safe;726 cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe; 727 727 } 728 728 } … … 737 737 auto dstEnd = dstAsTuple->types.end(); 738 738 while ( srcIt != srcEnd && dstIt != dstEnd ) { 739 Cost newCost = costCalc( * srcIt++, * dstIt++, s ymtab, env );739 Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env ); 740 740 if ( newCost == Cost::infinity ) { 741 741 return; … … 772 772 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 773 773 } 774 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 775 cost = Cost::zero; 776 // +1 for zero_t ->, +1 for disambiguation 777 cost.incSafe( maxIntCost + 2 ); 774 778 } 775 779 } … … 789 793 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 790 794 } 791 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {792 cost = Cost::zero;793 cost.incSafe( maxIntCost + 2 );794 795 } 795 796 } -
src/ResolvExpr/ConversionCost.h
r057298e r7030dab 10 10 // Created On : Sun May 17 09:37:28 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:13:00 201913 // Update Count : 612 // Last Modified On : Tue Oct 4 14:59:00 2019 13 // Update Count : 7 14 14 // 15 15 … … 74 74 75 75 // Some function pointer types, differ in return type. 76 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, 76 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool, 77 77 const ast::SymbolTable &, const ast::TypeEnvironment &)>; 78 using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,78 using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *, 79 79 const ast::SymbolTable &, const ast::TypeEnvironment &)>; 80 80 … … 83 83 protected: 84 84 const ast::Type * dst; 85 bool srcIsLvalue; 85 86 const ast::SymbolTable & symtab; 86 87 const ast::TypeEnvironment & env; … … 89 90 Cost cost; 90 91 91 ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,92 ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 92 93 const ast::TypeEnvironment & env, CostCalculation costCalc ) : 93 dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity ) 94 dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ), 95 costCalc( costCalc ), cost( Cost::infinity ) 94 96 {} 95 97 … … 114 116 115 117 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest, 116 const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func ); 118 bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, 119 PtrsCalculation func ); 117 120 118 121 } // namespace ResolvExpr -
src/ResolvExpr/CurrentObject.cc
r057298e r7030dab 21 21 #include <string> // for string, operator<<, allocator 22 22 23 #include "AST/Copy.hpp" // for shallowCopy 23 24 #include "AST/Expr.hpp" // for InitAlternative 24 25 #include "AST/GenericSubstitution.hpp" // for genericSubstitution 25 26 #include "AST/Init.hpp" // for Designation 26 27 #include "AST/Node.hpp" // for readonly 28 #include "AST/Print.hpp" // for readonly 27 29 #include "AST/Type.hpp" 28 30 #include "Common/Indenter.h" // for Indenter, operator<< … … 596 598 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {} 597 599 598 void setPosition( 599 std::deque< ptr< Expr > >::const_iterator begin, 600 void setPosition( 601 std::deque< ptr< Expr > >::const_iterator begin, 600 602 std::deque< ptr< Expr > >::const_iterator end 601 603 ) override { … … 637 639 auto res = eval(expr); 638 640 if ( ! res.second ) { 639 SemanticError( location, 641 SemanticError( location, 640 642 toString("Array designator must be a constant expression: ", expr ) ); 641 643 } … … 644 646 645 647 public: 646 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 648 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 647 649 : location( loc ), array( at ), base( at->base ) { 648 650 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) … … 655 657 656 658 void setPosition( const Expr * expr ) { 657 // need to permit integer-constant-expressions, including: integer constants, 658 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 // need to permit integer-constant-expressions, including: integer constants, 660 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 661 // cast expressions 660 662 if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 662 664 index = constExpr->intValue(); 663 665 } catch ( SemanticErrorException & ) { 664 SemanticError( expr, 666 SemanticError( expr, 665 667 "Constant expression of non-integral type in array designator: " ); 666 668 } 667 669 } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) { 668 670 setPosition( castExpr->arg ); 669 } else if ( 670 dynamic_cast< const SizeofExpr * >( expr ) 671 || dynamic_cast< const AlignofExpr * >( expr ) 671 } else if ( 672 dynamic_cast< const SizeofExpr * >( expr ) 673 || dynamic_cast< const AlignofExpr * >( expr ) 672 674 ) { 673 675 index = 0; 674 676 } else { 675 assertf( false, 677 assertf( false, 676 678 "bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 677 679 } 678 680 } 679 681 680 void setPosition( 681 std::deque< ptr< Expr > >::const_iterator begin, 682 void setPosition( 683 std::deque< ptr< Expr > >::const_iterator begin, 682 684 std::deque< ptr< Expr > >::const_iterator end 683 685 ) override { … … 758 760 } 759 761 760 AggregateIterator( 761 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 AggregateIterator( 763 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 764 const MemberList & ms ) 763 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 765 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 764 766 sub( genericSubstitution( i ) ) { 765 767 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) … … 768 770 769 771 public: 770 void setPosition( 771 std::deque< ptr< Expr > >::const_iterator begin, 772 void setPosition( 773 std::deque< ptr< Expr > >::const_iterator begin, 772 774 std::deque< ptr< Expr > >::const_iterator end 773 775 ) final { … … 786 788 return; 787 789 } 788 assertf( false, 790 assertf( false, 789 791 "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 790 792 } else { 791 assertf( false, 793 assertf( false, 792 794 "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() ); 793 795 } … … 803 805 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 804 806 // need to substitute for generic types so that casts are to concrete types 807 alt.type = shallowCopy(alt.type.get()); 805 808 PRINT( std::cerr << " type is: " << alt.type; ) 806 809 sub.apply( alt.type ); // also apply to designation?? … … 842 845 for ( InitAlternative & alt : ret ) { 843 846 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 844 alt.designation.get_and_mutate()->designators.emplace_front( 847 alt.designation.get_and_mutate()->designators.emplace_front( 845 848 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 846 849 } … … 897 900 class TupleIterator final : public AggregateIterator { 898 901 public: 899 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 900 : AggregateIterator( 901 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 903 : AggregateIterator( 904 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 905 ) {} 903 906 … … 926 929 return new UnionIterator{ loc, uit }; 927 930 } else { 928 assertf( 929 dynamic_cast< const EnumInstType * >( aggr )930 || dynamic_cast< const TypeInstType * >( aggr ),931 assertf( 932 dynamic_cast< const EnumInstType * >( type ) 933 || dynamic_cast< const TypeInstType * >( type ), 931 934 "Encountered unhandled ReferenceToType in createMemberIterator: %s", 932 935 toString( type ).c_str() ); … … 949 952 using DesignatorChain = std::deque< ptr< Expr > >; 950 953 PRINT( std::cerr << "___findNext" << std::endl; ) 951 954 952 955 // find all the d's 953 956 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts; … … 1013 1016 // set new designators 1014 1017 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 1015 Designation * actualDesignation = 1018 Designation * actualDesignation = 1016 1019 new Designation{ designation->location, DesignatorChain{d} }; 1017 1020 objStack.back()->setPosition( d ); // destroys d -
src/ResolvExpr/PolyCost.cc
r057298e r7030dab 58 58 59 59 // TODO: When the old PolyCost is torn out get rid of the _new suffix. 60 struct PolyCost_new { 60 class PolyCost_new { 61 const ast::SymbolTable &symtab; 62 public: 61 63 int result; 62 const ast::SymbolTable &symtab;63 64 const ast::TypeEnvironment &env_; 64 65 65 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :66 result( 0 ), symtab( symtab), env_( env ) {}66 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 67 : symtab( symtab ), result( 0 ), env_( env ) {} 67 68 68 69 void previsit( const ast::TypeInstType * type ) { -
src/ResolvExpr/RenameVars.cc
r057298e r7030dab 19 19 #include <utility> // for pair 20 20 21 #include "AST/ForallSubstitutionTable.hpp" 21 22 #include "AST/Pass.hpp" 22 23 #include "AST/Type.hpp" … … 30 31 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 31 32 33 #include "AST/Copy.hpp" 34 32 35 namespace ResolvExpr { 33 36 … … 37 40 int resetCount = 0; 38 41 ScopedMap< std::string, std::string > nameMap; 42 public: 43 ast::ForallSubstitutionTable subs; 39 44 40 public:41 45 void reset() { 42 46 level = 0; … … 44 48 } 45 49 46 using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;47 48 50 void rename( TypeInstType * type ) { 49 mapConstIteratorit = nameMap.find( type->name );51 auto it = nameMap.find( type->name ); 50 52 if ( it != nameMap.end() ) { 51 53 type->name = it->second; … … 65 67 // ditto for assertion names, the next level in 66 68 level++; 67 // acceptAll( td->assertions, *this ); 68 } // for 69 } // if 69 } 70 } 70 71 } 71 72 … … 77 78 78 79 const ast::TypeInstType * rename( const ast::TypeInstType * type ) { 79 mapConstIterator it = nameMap.find( type->name ); 80 // re-linking of base type handled by WithForallSubstitutor 81 82 // rename 83 auto it = nameMap.find( type->name ); 80 84 if ( it != nameMap.end() ) { 81 ast::TypeInstType * mutType = ast::mutate( type ); 82 mutType->name = it->second; 83 type = mutType; 85 // unconditionally mutate because map will *always* have different name, 86 // if this mutates, will *always* have been mutated by ForallSubstitutor above 87 ast::TypeInstType * mut = ast::mutate( type ); 88 mut->name = it->second; 89 type = mut; 84 90 } 91 85 92 return type; 86 93 } … … 88 95 template<typename NodeT> 89 96 const NodeT * openLevel( const NodeT * type ) { 90 if ( !type->forall.empty() ) { 91 nameMap.beginScope(); 92 // Load new names from this forall clause and perform renaming. 93 NodeT * mutType = ast::mutate( type ); 94 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 95 std::ostringstream output; 96 output << "_" << resetCount << "_" << level << "_" << td->name; 97 std::string newname( output.str() ); 98 nameMap[ td->name ] = newname; 99 ++level; 97 if ( type->forall.empty() ) return type; 100 98 101 ast::TypeDecl * decl = ast::mutate( td.get() ); 102 decl->name = newname; 103 td = decl; 104 } 99 nameMap.beginScope(); 100 101 // Load new names from this forall clause and perform renaming. 102 NodeT * mutType = ast::mutate( type ); 103 assert( type == mutType && "mutated type must be unique from ForallSubstitutor" ); 104 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 105 std::ostringstream output; 106 output << "_" << resetCount << "_" << level << "_" << td->name; 107 std::string newname = output.str(); 108 nameMap[ td->name ] = newname; 109 ++level; 110 111 ast::TypeDecl * mutDecl = ast::mutate( td.get() ); 112 assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" ); 113 mutDecl->name = newname; 114 // assertion above means `td = mutDecl;` is unnecessary 105 115 } 116 // assertion above means `type = mutType;` is unnecessary 117 106 118 return type; 107 119 } 108 120 109 template<typename NodeT> 110 const NodeT * closeLevel( const NodeT * type ) { 111 if ( !type->forall.empty() ) { 112 nameMap.endScope(); 113 } 114 return type; 121 void closeLevel( const ast::ParameterizedType * type ) { 122 if ( type->forall.empty() ) return; 123 124 nameMap.endScope(); 115 125 } 116 126 }; … … 119 129 RenamingData renaming; 120 130 121 struct RenameVars {131 struct RenameVars_old { 122 132 void previsit( TypeInstType * instType ) { 123 133 renaming.openLevel( (Type*)instType ); … … 130 140 renaming.closeLevel( type ); 131 141 } 142 }; 143 144 struct RenameVars_new /*: public ast::WithForallSubstitutor*/ { 145 #warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor 146 ast::ForallSubstitutionTable & subs = renaming.subs; 132 147 133 148 const ast::FunctionType * previsit( const ast::FunctionType * type ) { … … 146 161 return renaming.rename( renaming.openLevel( type ) ); 147 162 } 148 const ast::ParameterizedType *postvisit( const ast::ParameterizedType * type ) {149 re turn renaming.closeLevel( type );163 void postvisit( const ast::ParameterizedType * type ) { 164 renaming.closeLevel( type ); 150 165 } 151 166 }; … … 154 169 155 170 void renameTyVars( Type * t ) { 156 PassVisitor<RenameVars > renamer;171 PassVisitor<RenameVars_old> renamer; 157 172 t->accept( renamer ); 158 173 } 159 174 160 175 const ast::Type * renameTyVars( const ast::Type * t ) { 161 ast::Pass<RenameVars> renamer; 162 return t->accept( renamer ); 176 ast::Type *tc = ast::deepCopy(t); 177 ast::Pass<RenameVars_new> renamer; 178 // return t->accept( renamer ); 179 return tc->accept( renamer ); 163 180 } 164 181 -
src/ResolvExpr/ResolveTypeof.cc
r057298e r7030dab 99 99 // replace basetypeof(<enum>) by int 100 100 if ( dynamic_cast<EnumInstType*>(newType) ) { 101 Type* newerType = 102 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 101 Type* newerType = 102 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 103 103 newType->attributes }; 104 104 delete newType; 105 105 newType = newerType; 106 106 } 107 newType->get_qualifiers().val 107 newType->get_qualifiers().val 108 108 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals; 109 109 } else { 110 110 newType->get_qualifiers().val |= oldQuals; 111 111 } 112 112 113 113 return newType; 114 114 } … … 120 120 ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {} 121 121 122 void pre mutate( const ast::TypeofType * ) { visit_children = false; }122 void previsit( const ast::TypeofType * ) { visit_children = false; } 123 123 124 const ast::Type * post mutate( const ast::TypeofType * typeofType ) {124 const ast::Type * postvisit( const ast::TypeofType * typeofType ) { 125 125 // pass on null expression 126 126 if ( ! typeofType->expr ) return typeofType; … … 133 133 // typeof wrapping expression 134 134 ast::TypeEnvironment dummy; 135 ast::ptr< ast::Expr > newExpr = 135 ast::ptr< ast::Expr > newExpr = 136 136 resolveInVoidContext( typeofType->expr, localSymtab, dummy ); 137 137 assert( newExpr->result && ! newExpr->result->isVoid() ); … … 143 143 // replace basetypeof(<enum>) by int 144 144 if ( newType.as< ast::EnumInstType >() ) { 145 newType = new ast::BasicType{ 145 newType = new ast::BasicType{ 146 146 ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) }; 147 147 } 148 reset_qualifiers( 149 newType, 148 reset_qualifiers( 149 newType, 150 150 ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers ); 151 151 } else { … … 153 153 } 154 154 155 return newType ;155 return newType.release(); 156 156 } 157 157 }; -
src/ResolvExpr/Resolver.cc
r057298e r7030dab 1074 1074 const ast::Expr * postmutate( const ast::CastExpr * castExpr ) { 1075 1075 if ( 1076 castExpr->isGenerated 1076 castExpr->isGenerated == ast::GeneratedCast 1077 1077 && typesCompatible( castExpr->arg->result, castExpr->result ) 1078 1078 ) { … … 1128 1128 1129 1129 // set up and resolve expression cast to void 1130 ast:: CastExpr *untyped = new ast::CastExpr{ expr };1130 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr }; 1131 1131 CandidateRef choice = findUnfinishedKindExpression( 1132 1132 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() ); … … 1267 1267 }; 1268 1268 1269 void resolve( std::list< ast::ptr< ast::Decl> >& translationUnit ) {1269 void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) { 1270 1270 ast::Pass< Resolver_new > resolver; 1271 1271 accept_all( translationUnit, resolver ); … … 1301 1301 ast::ptr< ast::FunctionDecl > ret = functionDecl; 1302 1302 for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) { 1303 const ast::ptr< ast::DeclWithType> & d = functionDecl->type->params[i];1303 const ast::ptr< ast::DeclWithType > & d = functionDecl->type->params[i]; 1304 1304 1305 1305 if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) { … … 1318 1318 } 1319 1319 } 1320 return ret. get();1320 return ret.release(); 1321 1321 } 1322 1322 … … 1341 1341 // in case we decide to allow nested enums 1342 1342 GuardValue( inEnumDecl ); 1343 inEnumDecl = false;1343 inEnumDecl = true; 1344 1344 } 1345 1345 -
src/ResolvExpr/SatisfyAssertions.cpp
r057298e r7030dab 9 9 // Author : Aaron B. Moss 10 10 // Created On : Mon Jun 10 17:45:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Mon Jun 10 17:45:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 13:56:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 299 299 Cost cost; 300 300 301 OutType( 302 const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 301 OutType( 302 const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 303 303 const std::vector< DeferRef > & as, const ast::SymbolTable & symtab ) 304 304 : env( e ), open( o ), assns( as ), cost( Cost::zero ) { … … 306 306 for ( const DeferRef & assn : assns ) { 307 307 // compute conversion cost from satisfying decl to assertion 308 cost += computeConversionCost( 309 assn.match.adjType, assn.decl->get_type(), symtab, env );310 308 cost += computeConversionCost( 309 assn.match.adjType, assn.decl->get_type(), false, symtab, env ); 310 311 311 // mark vars+specialization on function-type assertions 312 const ast::FunctionType * func = 312 const ast::FunctionType * func = 313 313 GenPoly::getFunctionType( assn.match.cdata.id->get_type() ); 314 314 if ( ! func ) continue; … … 317 317 cost.decSpec( specCost( param->get_type() ) ); 318 318 } 319 319 320 320 cost.incVar( func->forall.size() ); 321 321 322 322 for ( const ast::TypeDecl * td : func->forall ) { 323 323 cost.decSpec( td->assertions.size() ); … … 329 329 }; 330 330 331 CandidateEnvMerger( 332 const ast::TypeEnvironment & env, const ast::OpenVarSet & open, 331 CandidateEnvMerger( 332 const ast::TypeEnvironment & env, const ast::OpenVarSet & open, 333 333 const ast::SymbolTable & syms ) 334 334 : crnt(), envs{ env }, opens{ open }, symtab( syms ) {} -
src/ResolvExpr/SatisfyAssertions.hpp
r057298e r7030dab 28 28 29 29 /// Recursively satisfies all assertions provided in a candidate; returns true if succeeds 30 void satisfyAssertions( 31 CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 30 void satisfyAssertions( 31 CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 32 32 std::vector<std::string> & errors ); 33 33 -
src/ResolvExpr/SpecCost.cc
r057298e r7030dab 10 10 // Created On : Tue Oct 02 15:50:00 2018 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Jun 19 10:43:00 2019 13 // Update Count : 2 14 // 15 12 // Last Modified On : Wed Jul 3 11:07:00 2019 13 // Update Count : 3 14 // 15 16 #include <cassert> 16 17 #include <limits> 17 18 #include <list> … … 129 130 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 130 131 132 #warning Should use a standard maybe_accept 133 void maybe_accept( ast::Type const * type ) { 134 if ( type ) { 135 auto node = type->accept( *visitor ); 136 assert( node == nullptr || node == type ); 137 } 138 } 139 131 140 // Update the minimum to the new lowest non-none value. 132 141 template<typename T> … … 134 143 for ( const auto & node : list ) { 135 144 count = -1; 136 ma pper( node )->accept( *visitor);145 maybe_accept( mapper( node ) ); 137 146 if ( count != -1 && count < minimum ) minimum = count; 138 147 } -
src/ResolvExpr/Unify.cc
r057298e r7030dab 25 25 #include <vector> 26 26 27 #include "AST/Copy.hpp" 27 28 #include "AST/Decl.hpp" 28 29 #include "AST/Node.hpp" 29 30 #include "AST/Pass.hpp" 31 #include "AST/Print.hpp" 30 32 #include "AST/Type.hpp" 31 33 #include "AST/TypeEnvironment.hpp" … … 135 137 findOpenVars( newSecond, open, closed, need, have, FirstOpen ); 136 138 137 return unifyExact( 138 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 140 } 140 141 … … 148 149 newFirst->get_qualifiers() = Type::Qualifiers(); 149 150 newSecond->get_qualifiers() = Type::Qualifiers(); 150 /// std::cerr << "first is "; 151 /// first->print( std::cerr ); 152 /// std::cerr << std::endl << "second is "; 153 /// second->print( std::cerr ); 154 /// std::cerr << std::endl << "newFirst is "; 155 /// newFirst->print( std::cerr ); 156 /// std::cerr << std::endl << "newSecond is "; 157 /// newSecond->print( std::cerr ); 158 /// std::cerr << std::endl; 151 159 152 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 160 153 delete newFirst; … … 170 163 ast::AssertionSet need, have; 171 164 172 ast::ptr<ast::Type> newFirst{ first }, newSecond{ second }; 173 env.apply( newFirst ); 174 env.apply( newSecond ); 175 reset_qualifiers( newFirst ); 176 reset_qualifiers( newSecond ); 165 ast::Type * newFirst = shallowCopy( first ); 166 ast::Type * newSecond = shallowCopy( second ); 167 newFirst ->qualifiers = {}; 168 newSecond->qualifiers = {}; 169 ast::ptr< ast::Type > t1_(newFirst ); 170 ast::ptr< ast::Type > t2_(newSecond); 177 171 178 172 return unifyExact( 179 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 173 env.apply( newFirst ).node, 174 env.apply( newSecond ).node, 175 newEnv, need, have, open, noWiden(), symtab ); 180 176 } 181 177 … … 326 322 327 323 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) { 328 /// std::cerr << "assertion set is" << std::endl;329 /// printAssertionSet( assertions, std::cerr, 8 );330 /// std::cerr << "looking for ";331 /// assert->print( std::cerr );332 /// std::cerr << std::endl;333 324 AssertionSet::iterator i = assertions.find( assert ); 334 325 if ( i != assertions.end() ) { 335 /// std::cerr << "found it!" << std::endl;336 326 i->second.isUsed = true; 337 327 } // if … … 943 933 944 934 private: 945 template< typename RefType > 946 const RefType * handleRefType( const RefType * inst, const ast::Type * other ) { 935 // Returns: other, cast as XInstType 936 // Assigns this->result: whether types are compatible (up to generic parameters) 937 template< typename XInstType > 938 const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) { 947 939 // check that the other type is compatible and named the same 948 auto otherInst = dynamic_cast< const RefType * >( other );949 result = otherInst && inst->name == otherInst->name;940 auto otherInst = dynamic_cast< const XInstType * >( other ); 941 this->result = otherInst && inst->name == otherInst->name; 950 942 return otherInst; 951 943 } … … 968 960 } 969 961 970 template< typename RefType >971 void handleGenericRefType( const RefType * inst, const ast::Type * other ) {962 template< typename XInstType > 963 void handleGenericRefType( const XInstType * inst, const ast::Type * other ) { 972 964 // check that other type is compatible and named the same 973 const RefType * inst2= handleRefType( inst, other );974 if ( ! inst2) return;965 const XInstType * otherInst = handleRefType( inst, other ); 966 if ( ! this->result ) return; 975 967 976 968 // check that parameters of types unify, if any 977 969 const std::vector< ast::ptr< ast::Expr > > & params = inst->params; 978 const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;970 const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params; 979 971 980 972 auto it = params.begin(); … … 1202 1194 // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and 1203 1195 // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1 1204 ast::ptr<ast::Type> t1{ type1 }, t2{ type2 }; 1205 reset_qualifiers( t1 ); 1206 reset_qualifiers( t2 ); 1196 ast::Type * t1 = shallowCopy(type1.get()); 1197 ast::Type * t2 = shallowCopy(type2.get()); 1198 t1->qualifiers = {}; 1199 t2->qualifiers = {}; 1200 ast::ptr< ast::Type > t1_(t1); 1201 ast::ptr< ast::Type > t2_(t2); 1207 1202 1208 1203 if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) { 1209 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1210 1211 1204 // if exact unification on unqualified types, try to merge qualifiers 1212 1205 if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) { 1213 common = type1;1214 reset_qualifiers( common, q1 | q2 );1206 t1->qualifiers = q1 | q2; 1207 common = t1; 1215 1208 return true; 1216 1209 } else { … … 1219 1212 1220 1213 } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) { 1221 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1222 1223 1214 // no exact unification, but common type 1224 reset_qualifiers( common, q1 | q2 ); 1215 auto c = shallowCopy(common.get()); 1216 c->qualifiers = q1 | q2; 1217 common = c; 1225 1218 return true; 1226 1219 } else { -
src/ResolvExpr/typeops.h
r057298e r7030dab 10 10 // Created On : Sun May 17 07:28:22 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:36:00 201913 // Update Count : 512 // Last Modified On : Tue Oct 1 09:45:00 2019 13 // Update Count : 6 14 14 // 15 15 … … 83 83 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 84 84 Cost castCost( 85 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,86 const ast:: TypeEnvironment & env );85 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 86 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 87 87 88 88 // in ConversionCost.cc … … 90 90 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 91 91 Cost conversionCost( 92 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,93 const ast:: TypeEnvironment & env );92 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 93 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 94 94 95 95 // in AlternativeFinder.cc -
src/SymTab/Autogen.h
r057298e r7030dab 21 21 22 22 #include "AST/Decl.hpp" 23 #include "AST/Eval.hpp" 23 24 #include "AST/Expr.hpp" 24 25 #include "AST/Init.hpp" … … 265 266 } 266 267 267 ast::ptr< ast::Expr > begin, end, cmp, update; 268 ast::ptr< ast::Expr > begin, end; 269 std::string cmp, update; 268 270 269 271 if ( forward ) { … … 271 273 begin = ast::ConstantExpr::from_int( loc, 0 ); 272 274 end = array->dimension; 273 cmp = new ast::NameExpr{ loc, "?<?" };274 update = new ast::NameExpr{ loc, "++?" };275 cmp = "?<?"; 276 update = "++?"; 275 277 } else { 276 278 // generate: for ( int i = N-1; i >= 0; --i ) 277 begin = new ast::UntypedExpr{ 278 loc, new ast::NameExpr{ loc, "?-?" }, 279 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } }; 279 begin = ast::call( 280 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) ); 280 281 end = ast::ConstantExpr::from_int( loc, 0 ); 281 cmp = new ast::NameExpr{ loc, "?>=?" };282 update = new ast::NameExpr{ loc, "--?" };282 cmp = "?>=?"; 283 update = "--?"; 283 284 } 284 285 … … 286 287 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 287 288 new ast::SingleInit{ loc, begin } }; 288 289 ast::ptr< ast::Expr > cond = new ast::UntypedExpr{ 290 loc, cmp, { new ast::VariableExpr{ loc, index }, end } }; 291 292 ast::ptr< ast::Expr > inc = new ast::UntypedExpr{ 293 loc, update, { new ast::VariableExpr{ loc, index } } }; 294 295 ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{ 296 loc, new ast::NameExpr{ loc, "?[?]" }, 297 { dstParam, new ast::VariableExpr{ loc, index } } }; 289 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index }; 290 291 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end ); 292 293 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar ); 294 295 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar ); 298 296 299 297 // srcParam must keep track of the array indices to build the source parameter and/or 300 298 // array list initializer 301 srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );299 srcParam.addArrayIndex( indexVar, array->dimension ); 302 300 303 301 // for stmt's body, eventually containing call … … 385 383 if ( isUnnamedBitfield( obj ) ) return {}; 386 384 387 ast::ptr< ast::Type > addCast = nullptr;385 ast::ptr< ast::Type > addCast; 388 386 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) { 389 387 assert( dstParam->result ); -
src/SynTree/Statement.h
r057298e r7030dab 518 518 class ImplicitCtorDtorStmt : public Statement { 519 519 public: 520 // Non-owned pointer to the constructor/destructor statement520 // the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere 521 521 Statement * callStmt; 522 522 -
src/Tuples/Explode.cc
r057298e r7030dab 129 129 for ( const ast::Expr * expr : tupleExpr->exprs ) { 130 130 exprs.emplace_back( applyCast( expr, false ) ); 131 //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );132 131 } 133 132 if ( first ) { -
src/Tuples/Explode.h
r057298e r7030dab 210 210 } 211 211 // Cast a reference away to a value-type to allow further explosion. 212 if ( dynamic_cast< const ast::ReferenceType *>( local->result.get()) ) {212 if ( local->result.as< ast::ReferenceType >() ) { 213 213 local = new ast::CastExpr{ local, tupleType }; 214 214 } … … 220 220 // delete idx; 221 221 } 222 // delete local;223 222 } 224 223 } else { -
src/Tuples/TupleAssignment.cc
r057298e r7030dab 465 465 // resolve ctor/dtor for the new object 466 466 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 467 InitTweak::genCtorInit( location, ret ), spotter.crntFinder. symtab);467 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms ); 468 468 // remove environments from subexpressions of stmtExpr 469 469 ast::Pass< EnvRemover > rm{ env }; … … 560 560 // resolve the cast expression so that rhsCand return type is bound by the cast 561 561 // type as needed, and transfer the resulting environment 562 ResolvExpr::CandidateFinder finder{ spotter.crntFinder. symtab, env };562 ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env }; 563 563 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 564 564 assert( finder.candidates.size() == 1 ); … … 609 609 // explode the LHS so that each field of a tuple-valued expr is assigned 610 610 ResolvExpr::CandidateList lhs; 611 explode( *lhsCand, crntFinder. symtab, back_inserter(lhs), true );611 explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true ); 612 612 for ( ResolvExpr::CandidateRef & cand : lhs ) { 613 613 // each LHS value must be a reference - some come in with a cast, if not … … 629 629 if ( isTuple( rhsCand->expr ) ) { 630 630 // multiple assignment 631 explode( *rhsCand, crntFinder. symtab, back_inserter(rhs), true );631 explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true ); 632 632 matcher.reset( 633 633 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); … … 648 648 // multiple assignment 649 649 ResolvExpr::CandidateList rhs; 650 explode( rhsCand, crntFinder. symtab, back_inserter(rhs), true );650 explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true ); 651 651 matcher.reset( 652 652 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); … … 678 678 ) 679 679 680 ResolvExpr::CandidateFinder finder{ crntFinder. symtab, matcher->env };680 ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env }; 681 681 682 682 try { -
src/Tuples/TupleExpansion.cc
r057298e r7030dab 323 323 std::vector<ast::ptr<ast::Type>> types; 324 324 ast::CV::Qualifiers quals{ 325 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |325 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | 326 326 ast