Changeset 24d6572 for src/AST/Pass.proto.hpp
- Timestamp:
- Jun 12, 2023, 2:45:32 PM (2 years ago)
- Branches:
- ast-experimental, master
- Children:
- 62d62db
- Parents:
- 34b4268 (diff), 251ce80 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Pass.proto.hpp
r34b4268 r24d6572 17 17 // IWYU pragma: private, include "Pass.hpp" 18 18 19 #include "Common/Iterate.hpp" 19 20 #include "Common/Stats/Heap.h" 20 21 21 namespace ast { 22 template<typename core_t> 23 class Pass; 24 25 class TranslationUnit; 26 27 struct PureVisitor; 28 29 template<typename node_t> 30 node_t * deepCopy( const node_t * localRoot ); 31 32 namespace __pass { 33 typedef std::function<void( void * )> cleanup_func_t; 34 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t; 35 36 37 // boolean reference that may be null 38 // either refers to a boolean value or is null and returns true 39 class bool_ref { 40 public: 41 bool_ref() = default; 42 ~bool_ref() = default; 43 44 operator bool() { return m_ref ? *m_ref : true; } 45 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; } 46 47 private: 48 49 friend class visit_children_guard; 50 51 bool * set( bool * val ) { 52 bool * prev = m_ref; 53 m_ref = val; 54 return prev; 55 } 56 57 bool * m_ref = nullptr; 22 template<typename core_t> class Pass; 23 class TranslationUnit; 24 struct PureVisitor; 25 template<typename node_t> node_t * deepCopy( const node_t * ); 26 } 27 28 #ifdef PEDANTIC_PASS_ASSERT 29 #define __pedantic_pass_assert(...) assert(__VA_ARGS__) 30 #define __pedantic_pass_assertf(...) assertf(__VA_ARGS__) 31 #else 32 #define __pedantic_pass_assert(...) 33 #define __pedantic_pass_assertf(...) 34 #endif 35 36 namespace ast::__pass { 37 38 typedef std::function<void( void * )> cleanup_func_t; 39 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t; 40 41 // boolean reference that may be null 42 // either refers to a boolean value or is null and returns true 43 class bool_ref { 44 public: 45 bool_ref() = default; 46 ~bool_ref() = default; 47 48 operator bool() { return m_ref ? *m_ref : true; } 49 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; } 50 51 private: 52 53 friend class visit_children_guard; 54 55 bool * set( bool * val ) { 56 bool * prev = m_ref; 57 m_ref = val; 58 return prev; 59 } 60 61 bool * m_ref = nullptr; 62 }; 63 64 // Implementation of the guard value 65 // Created inside the visit scope 66 class guard_value { 67 public: 68 /// Push onto the cleanup 69 guard_value( at_cleanup_t * at_cleanup ) { 70 if( at_cleanup ) { 71 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 72 push( std::move( func ), val ); 73 }; 74 } 75 } 76 77 ~guard_value() { 78 while( !cleanups.empty() ) { 79 auto& cleanup = cleanups.top(); 80 cleanup.func( cleanup.val ); 81 cleanups.pop(); 82 } 83 } 84 85 void push( cleanup_func_t && func, void* val ) { 86 cleanups.emplace( std::move(func), val ); 87 } 88 89 private: 90 struct cleanup_t { 91 cleanup_func_t func; 92 void * val; 93 94 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 58 95 }; 59 96 60 // Implementation of the guard value 61 // Created inside the visit scope 62 class guard_value { 63 public: 64 /// Push onto the cleanup 65 guard_value( at_cleanup_t * at_cleanup ) { 66 if( at_cleanup ) { 67 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 68 push( std::move( func ), val ); 69 }; 97 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 98 }; 99 100 // Guard structure implementation for whether or not children should be visited 101 class visit_children_guard { 102 public: 103 104 visit_children_guard( bool_ref * ref ) 105 : m_val ( true ) 106 , m_prev( ref ? ref->set( &m_val ) : nullptr ) 107 , m_ref ( ref ) 108 {} 109 110 ~visit_children_guard() { 111 if( m_ref ) { 112 m_ref->set( m_prev ); 113 } 114 } 115 116 operator bool() { return m_val; } 117 118 private: 119 bool m_val; 120 bool * m_prev; 121 bool_ref * m_ref; 122 }; 123 124 /// "Short hand" to check if this is a valid previsit function 125 /// Mostly used to make the static_assert look (and print) prettier 126 template<typename core_t, typename node_t> 127 struct is_valid_previsit { 128 using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) ); 129 130 static constexpr bool value = std::is_void< ret_t >::value || 131 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value; 132 }; 133 134 /// The result is a single node. 135 template< typename node_t > 136 struct result1 { 137 bool differs = false; 138 const node_t * value = nullptr; 139 140 template< typename object_t, typename super_t, typename field_t > 141 void apply( object_t * object, field_t super_t::* field ) { 142 object->*field = value; 143 } 144 }; 145 146 /// The result is a container of statements. 147 template< template<class...> class container_t > 148 struct resultNstmt { 149 /// The delta/change on a single node. 150 struct delta { 151 ptr<Stmt> new_val; 152 ssize_t old_idx; 153 bool is_old; 154 155 delta(const Stmt * s, ssize_t i, bool old) : 156 new_val(s), old_idx(i), is_old(old) {} 157 }; 158 159 bool differs = false; 160 container_t< delta > values; 161 162 template< typename object_t, typename super_t, typename field_t > 163 void apply( object_t * object, field_t super_t::* field ) { 164 field_t & container = object->*field; 165 __pedantic_pass_assert( container.size() <= values.size() ); 166 167 auto cit = enumerate(container).begin(); 168 169 container_t<ptr<Stmt>> nvals; 170 for ( delta & d : values ) { 171 if ( d.is_old ) { 172 __pedantic_pass_assert( cit.idx <= d.old_idx ); 173 std::advance( cit, d.old_idx - cit.idx ); 174 nvals.push_back( std::move( (*cit).val ) ); 175 } else { 176 nvals.push_back( std::move( d.new_val ) ); 70 177 } 71 178 } 72 179 73 ~guard_value() { 74 while( !cleanups.empty() ) { 75 auto& cleanup = cleanups.top(); 76 cleanup.func( cleanup.val ); 77 cleanups.pop(); 78 } 79 } 80 81 void push( cleanup_func_t && func, void* val ) { 82 cleanups.emplace( std::move(func), val ); 83 } 84 85 private: 86 struct cleanup_t { 87 cleanup_func_t func; 88 void * val; 89 90 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 91 }; 92 93 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 94 }; 95 96 // Guard structure implementation for whether or not children should be visited 97 class visit_children_guard { 98 public: 99 100 visit_children_guard( bool_ref * ref ) 101 : m_val ( true ) 102 , m_prev( ref ? ref->set( &m_val ) : nullptr ) 103 , m_ref ( ref ) 104 {} 105 106 ~visit_children_guard() { 107 if( m_ref ) { 108 m_ref->set( m_prev ); 109 } 110 } 111 112 operator bool() { return m_val; } 113 114 private: 115 bool m_val; 116 bool * m_prev; 117 bool_ref * m_ref; 118 }; 119 120 /// "Short hand" to check if this is a valid previsit function 121 /// Mostly used to make the static_assert look (and print) prettier 180 container = std::move(nvals); 181 } 182 183 template< template<class...> class incontainer_t > 184 void take_all( incontainer_t<ptr<Stmt>> * stmts ) { 185 if ( !stmts || stmts->empty() ) return; 186 187 std::transform( stmts->begin(), stmts->end(), std::back_inserter( values ), 188 [](ast::ptr<ast::Stmt>& stmt) -> delta { 189 return delta( stmt.release(), -1, false ); 190 }); 191 stmts->clear(); 192 differs = true; 193 } 194 195 template< template<class...> class incontainer_t > 196 void take_all( incontainer_t<ptr<Decl>> * decls ) { 197 if ( !decls || decls->empty() ) return; 198 199 std::transform( decls->begin(), decls->end(), std::back_inserter( values ), 200 [](ast::ptr<ast::Decl>& decl) -> delta { 201 ast::Decl const * d = decl.release(); 202 return delta( new DeclStmt( d->location, d ), -1, false ); 203 }); 204 decls->clear(); 205 differs = true; 206 } 207 }; 208 209 /// The result is a container of nodes. 210 template< template<class...> class container_t, typename node_t > 211 struct resultN { 212 bool differs = false; 213 container_t<ptr<node_t>> values; 214 215 template< typename object_t, typename super_t, typename field_t > 216 void apply( object_t * object, field_t super_t::* field ) { 217 field_t & container = object->*field; 218 __pedantic_pass_assert( container.size() == values.size() ); 219 220 for ( size_t i = 0; i < container.size(); ++i ) { 221 // Take all the elements that are different in 'values' 222 // and swap them into 'container' 223 if ( values[i] != nullptr ) swap(container[i], values[i]); 224 } 225 // Now the original containers should still have the unchanged values 226 // but also contain the new values. 227 } 228 }; 229 230 /// Used by previsit implementation 231 /// We need to reassign the result to 'node', unless the function 232 /// returns void, then we just leave 'node' unchanged 233 template<bool is_void> 234 struct __assign; 235 236 template<> 237 struct __assign<true> { 122 238 template<typename core_t, typename node_t> 123 struct is_valid_previsit { 124 using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) ); 125 126 static constexpr bool value = std::is_void< ret_t >::value || 127 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value; 128 }; 129 130 /// The result is a single node. 131 template< typename node_t > 132 struct result1 { 133 bool differs = false; 134 const node_t * value = nullptr; 135 136 template< typename object_t, typename super_t, typename field_t > 137 void apply( object_t *, field_t super_t::* field ); 138 }; 139 140 /// The result is a container of statements. 141 template< template<class...> class container_t > 142 struct resultNstmt { 143 /// The delta/change on a single node. 144 struct delta { 145 ptr<Stmt> new_val; 146 ssize_t old_idx; 147 bool is_old; 148 149 delta(const Stmt * s, ssize_t i, bool old) : 150 new_val(s), old_idx(i), is_old(old) {} 151 }; 152 153 bool differs = false; 154 container_t< delta > values; 155 156 template< typename object_t, typename super_t, typename field_t > 157 void apply( object_t *, field_t super_t::* field ); 158 159 template< template<class...> class incontainer_t > 160 void take_all( incontainer_t<ptr<Stmt>> * stmts ); 161 162 template< template<class...> class incontainer_t > 163 void take_all( incontainer_t<ptr<Decl>> * decls ); 164 }; 165 166 /// The result is a container of nodes. 167 template< template<class...> class container_t, typename node_t > 168 struct resultN { 169 bool differs = false; 170 container_t<ptr<node_t>> values; 171 172 template< typename object_t, typename super_t, typename field_t > 173 void apply( object_t *, field_t super_t::* field ); 174 }; 175 176 /// Used by previsit implementation 177 /// We need to reassign the result to 'node', unless the function 178 /// returns void, then we just leave 'node' unchanged 179 template<bool is_void> 180 struct __assign; 181 182 template<> 183 struct __assign<true> { 184 template<typename core_t, typename node_t> 185 static inline void result( core_t & core, const node_t * & node ) { 186 core.previsit( node ); 187 } 188 }; 189 190 template<> 191 struct __assign<false> { 192 template<typename core_t, typename node_t> 193 static inline void result( core_t & core, const node_t * & node ) { 194 node = core.previsit( node ); 195 assertf(node, "Previsit must not return NULL"); 196 } 197 }; 198 199 /// Used by postvisit implementation 200 /// We need to return the result unless the function 201 /// returns void, then we just return the original node 202 template<bool is_void> 203 struct __return; 204 205 template<> 206 struct __return<true> { 207 template<typename core_t, typename node_t> 208 static inline const node_t * result( core_t & core, const node_t * & node ) { 209 core.postvisit( node ); 210 return node; 211 } 212 }; 213 214 template<> 215 struct __return<false> { 216 template<typename core_t, typename node_t> 217 static inline auto result( core_t & core, const node_t * & node ) { 218 return core.postvisit( node ); 219 } 220 }; 221 222 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 223 // Deep magic (a.k.a template meta programming) to make the templated visitor work 224 // Basically the goal is to make 2 previsit 225 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 226 // 'pass.previsit( node )' that compiles will be used for that node for that type 227 // This requires that this option only compile for passes that actually define an appropriate visit. 228 // SFINAE will make sure the compilation errors in this function don't halt the build. 229 // See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE 230 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing. 231 // This is needed only to eliminate the need for passes to specify any kind of handlers. 232 // The second implementation only works because it has a lower priority. This is due to the bogus last parameter. 233 // The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0 234 // the first implementation takes priority in regards to overloading. 235 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 236 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 239 static inline void result( core_t & core, const node_t * & node ) { 240 core.previsit( node ); 241 } 242 }; 243 244 template<> 245 struct __assign<false> { 237 246 template<typename core_t, typename node_t> 238 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 239 static_assert( 240 is_valid_previsit<core_t, node_t>::value, 241 "Previsit may not change the type of the node. It must return its paremeter or void." 242 ); 243 244 __assign< 245 std::is_void< 246 decltype( core.previsit( node ) ) 247 >::value 248 >::result( core, node ); 249 } 250 247 static inline void result( core_t & core, const node_t * & node ) { 248 node = core.previsit( node ); 249 assertf(node, "Previsit must not return NULL"); 250 } 251 }; 252 253 /// Used by postvisit implementation 254 /// We need to return the result unless the function 255 /// returns void, then we just return the original node 256 template<bool is_void> 257 struct __return; 258 259 template<> 260 struct __return<true> { 251 261 template<typename core_t, typename node_t> 252 static inline auto previsit( core_t &, const node_t *, long ) {} 253 254 // PostVisit : never mutates the passed pointer but may return a different node 262 static inline const node_t * result( core_t & core, const node_t * & node ) { 263 core.postvisit( node ); 264 return node; 265 } 266 }; 267 268 template<> 269 struct __return<false> { 255 270 template<typename core_t, typename node_t> 256 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 257 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 258 { 259 return __return< 260 std::is_void< 261 decltype( core.postvisit( node ) ) 262 >::value 263 >::result( core, node ); 264 } 265 266 template<typename core_t, typename node_t> 267 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 268 269 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 270 // Deep magic (a.k.a template meta programming) continued 271 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit 272 // from in order to get extra functionallity for example 273 // class ErrorChecker : WithShortCircuiting { ... }; 274 // Pass<ErrorChecker> checker; 275 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting 276 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched 277 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 278 // For several accessories, the feature is enabled by detecting that a specific field is present 279 // Use a macro the encapsulate the logic of detecting a particular field 280 // The type is not strictly enforced but does match the accessory 281 #define FIELD_PTR( name, default_type ) \ 282 template< typename core_t > \ 283 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 271 static inline auto result( core_t & core, const node_t * & node ) { 272 return core.postvisit( node ); 273 } 274 }; 275 276 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 277 // Deep magic (a.k.a template meta programming) to make the templated visitor work 278 // Basically the goal is to make 2 previsit 279 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 280 // 'pass.previsit( node )' that compiles will be used for that node for that type 281 // This requires that this option only compile for passes that actually define an appropriate visit. 282 // SFINAE will make sure the compilation errors in this function don't halt the build. 283 // See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE 284 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing. 285 // This is needed only to eliminate the need for passes to specify any kind of handlers. 286 // The second implementation only works because it has a lower priority. This is due to the bogus last parameter. 287 // The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0 288 // the first implementation takes priority in regards to overloading. 289 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 290 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 291 template<typename core_t, typename node_t> 292 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 293 static_assert( 294 is_valid_previsit<core_t, node_t>::value, 295 "Previsit may not change the type of the node. It must return its paremeter or void." 296 ); 297 298 __assign< 299 std::is_void< 300 decltype( core.previsit( node ) ) 301 >::value 302 >::result( core, node ); 303 } 304 305 template<typename core_t, typename node_t> 306 static inline auto previsit( core_t &, const node_t *, long ) {} 307 308 // PostVisit : never mutates the passed pointer but may return a different node 309 template<typename core_t, typename node_t> 310 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 311 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 312 { 313 return __return< 314 std::is_void< 315 decltype( core.postvisit( node ) ) 316 >::value 317 >::result( core, node ); 318 } 319 320 template<typename core_t, typename node_t> 321 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 322 323 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 324 // Deep magic (a.k.a template meta programming) continued 325 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit 326 // from in order to get extra functionallity for example 327 // class ErrorChecker : WithShortCircuiting { ... }; 328 // Pass<ErrorChecker> checker; 329 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting 330 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched 331 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 332 // For several accessories, the feature is enabled by detecting that a specific field is present 333 // Use a macro the encapsulate the logic of detecting a particular field 334 // The type is not strictly enforced but does match the accessory 335 #define FIELD_PTR( name, default_type ) \ 336 template< typename core_t > \ 337 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 338 \ 339 template< typename core_t > \ 340 static inline default_type * name( core_t &, long ) { return nullptr; } 341 342 // List of fields and their expected types 343 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 344 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 345 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) 346 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > ) 347 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > ) 348 FIELD_PTR( visit_children, __pass::bool_ref ) 349 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 350 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 351 352 // Remove the macro to make sure we don't clash 353 #undef FIELD_PTR 354 355 template< typename core_t > 356 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 357 // Stats::Heap::stacktrace_push(core_t::traceId); 358 } 359 360 template< typename core_t > 361 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 362 // Stats::Heap::stacktrace_pop(); 363 } 364 365 template< typename core_t > 366 static void beginTrace(core_t &, long) {} 367 368 template< typename core_t > 369 static void endTrace(core_t &, long) {} 370 371 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 372 // If on_error() returns false, the error will be ignored. By default, it returns true. 373 374 template< typename core_t > 375 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 376 377 template< typename core_t > 378 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 379 return core.on_error(decl); 380 } 381 382 template< typename core_t, typename node_t > 383 static auto make_location_guard( core_t & core, node_t * node, int ) 384 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) { 385 ValueGuardPtr<const CodeLocation *> guard( &core.location ); 386 core.location = &node->location; 387 return guard; 388 } 389 390 template< typename core_t, typename node_t > 391 static auto make_location_guard( core_t &, node_t *, long ) -> int { 392 return 0; 393 } 394 395 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. 396 // All passes which have such functions are assumed desire this behaviour 397 // detect it using the same strategy 398 namespace scope { 399 template<typename core_t> 400 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 401 core.beginScope(); 402 } 403 404 template<typename core_t> 405 static inline void enter( core_t &, long ) {} 406 407 template<typename core_t> 408 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 409 core.endScope(); 410 } 411 412 template<typename core_t> 413 static inline void leave( core_t &, long ) {} 414 } // namespace scope 415 416 // Certain passes desire an up to date symbol table automatically 417 // detect the presence of a member name `symtab` and call all the members appropriately 418 namespace symtab { 419 // Some simple scoping rules 420 template<typename core_t> 421 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 422 core.symtab.enterScope(); 423 } 424 425 template<typename core_t> 426 static inline auto enter( core_t &, long ) {} 427 428 template<typename core_t> 429 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 430 core.symtab.leaveScope(); 431 } 432 433 template<typename core_t> 434 static inline auto leave( core_t &, long ) {} 435 436 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 437 // Create macro to condense these common patterns 438 #define SYMTAB_FUNC1( func, type ) \ 439 template<typename core_t> \ 440 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 441 core.symtab.func( arg ); \ 442 } \ 284 443 \ 285 template< typename core_t > \ 286 static inline default_type * name( core_t &, long ) { return nullptr; } 287 288 // List of fields and their expected types 289 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 290 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 291 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) 292 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > ) 293 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > ) 294 FIELD_PTR( visit_children, __pass::bool_ref ) 295 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 296 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 297 298 // Remove the macro to make sure we don't clash 299 #undef FIELD_PTR 300 301 template< typename core_t > 302 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 303 // Stats::Heap::stacktrace_push(core_t::traceId); 304 } 305 306 template< typename core_t > 307 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 308 // Stats::Heap::stacktrace_pop(); 309 } 310 311 template< typename core_t > 312 static void beginTrace(core_t &, long) {} 313 314 template< typename core_t > 315 static void endTrace(core_t &, long) {} 316 317 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 318 // If onError() returns false, the error will be ignored. By default, it returns true. 319 320 template< typename core_t > 321 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 322 323 template< typename core_t > 324 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 325 return core.on_error(decl); 326 } 327 328 template< typename core_t, typename node_t > 329 static auto make_location_guard( core_t & core, node_t * node, int ) 330 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) { 331 ValueGuardPtr<const CodeLocation *> guard( &core.location ); 332 core.location = &node->location; 333 return guard; 334 } 335 336 template< typename core_t, typename node_t > 337 static auto make_location_guard( core_t &, node_t *, long ) -> int { 338 return 0; 339 } 340 341 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. 342 // All passes which have such functions are assumed desire this behaviour 343 // detect it using the same strategy 344 namespace scope { 345 template<typename core_t> 346 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 347 core.beginScope(); 348 } 349 350 template<typename core_t> 351 static inline void enter( core_t &, long ) {} 352 353 template<typename core_t> 354 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 355 core.endScope(); 356 } 357 358 template<typename core_t> 359 static inline void leave( core_t &, long ) {} 360 } // namespace scope 361 362 // Certain passes desire an up to date symbol table automatically 363 // detect the presence of a member name `symtab` and call all the members appropriately 364 namespace symtab { 365 // Some simple scoping rules 366 template<typename core_t> 367 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 368 core.symtab.enterScope(); 369 } 370 371 template<typename core_t> 372 static inline auto enter( core_t &, long ) {} 373 374 template<typename core_t> 375 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 376 core.symtab.leaveScope(); 377 } 378 379 template<typename core_t> 380 static inline auto leave( core_t &, long ) {} 381 382 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 383 // Create macro to condense these common patterns 384 #define SYMTAB_FUNC1( func, type ) \ 385 template<typename core_t> \ 386 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 387 core.symtab.func( arg ); \ 388 } \ 389 \ 390 template<typename core_t> \ 391 static inline void func( core_t &, long, type ) {} 392 393 #define SYMTAB_FUNC2( func, type1, type2 ) \ 394 template<typename core_t> \ 395 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 396 core.symtab.func( arg1, arg2 ); \ 397 } \ 398 \ 399 template<typename core_t> \ 400 static inline void func( core_t &, long, type1, type2 ) {} 401 402 SYMTAB_FUNC1( addId , const DeclWithType * ); 403 SYMTAB_FUNC1( addType , const NamedTypeDecl * ); 404 SYMTAB_FUNC1( addStruct , const StructDecl * ); 405 SYMTAB_FUNC1( addEnum , const EnumDecl * ); 406 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 407 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 408 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 409 410 // A few extra functions have more complicated behaviour, they are hand written 411 template<typename core_t> 412 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 413 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 414 for ( const auto & param : decl->params ) { 415 fwd->params.push_back( deepCopy( param.get() ) ); 416 } 417 core.symtab.addStruct( fwd ); 418 } 419 420 template<typename core_t> 421 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 422 423 template<typename core_t> 424 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 425 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name ); 426 for ( const auto & param : decl->params ) { 427 fwd->params.push_back( deepCopy( param.get() ) ); 428 } 429 core.symtab.addUnion( fwd ); 430 } 431 432 template<typename core_t> 433 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 434 435 template<typename core_t> 436 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 437 if ( ! core.symtab.lookupStruct( str ) ) { 438 core.symtab.addStruct( str ); 439 } 440 } 441 442 template<typename core_t> 443 static inline void addStruct( core_t &, long, const std::string & ) {} 444 445 template<typename core_t> 446 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 447 if ( ! core.symtab.lookupUnion( str ) ) { 448 core.symtab.addUnion( str ); 449 } 450 } 451 452 template<typename core_t> 453 static inline void addUnion( core_t &, long, const std::string & ) {} 454 455 #undef SYMTAB_FUNC1 456 #undef SYMTAB_FUNC2 457 } // namespace symtab 458 459 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 460 // Detect the presence of a member name `subs` and call all members appropriately 461 namespace forall { 462 // Some simple scoping rules 463 template<typename core_t> 464 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 465 -> decltype( core.subs, void() ) { 466 if ( ! type->forall.empty() ) core.subs.beginScope(); 467 } 468 469 template<typename core_t> 470 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 471 472 template<typename core_t> 473 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 474 -> decltype( core.subs, void() ) { 475 if ( ! type->forall.empty() ) { core.subs.endScope(); } 476 } 477 478 template<typename core_t> 479 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 480 481 // Replaces a TypeInstType's base TypeDecl according to the table 482 template<typename core_t> 483 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 484 -> decltype( core.subs, void() ) { 485 inst = ast::mutate_field( 486 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 487 } 488 489 template<typename core_t> 490 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 491 492 } // namespace forall 493 494 // For passes that need access to the global context. Sreaches `translationUnit` 495 namespace translation_unit { 496 template<typename core_t> 497 static inline auto get_cptr( core_t & core, int ) 498 -> decltype( &core.translationUnit ) { 499 return &core.translationUnit; 500 } 501 502 template<typename core_t> 503 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 504 return nullptr; 505 } 506 } 507 508 template<typename core_t> 509 static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) { 444 template<typename core_t> \ 445 static inline void func( core_t &, long, type ) {} 446 447 #define SYMTAB_FUNC2( func, type1, type2 ) \ 448 template<typename core_t> \ 449 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 450 core.symtab.func( arg1, arg2 ); \ 451 } \ 452 \ 453 template<typename core_t> \ 454 static inline void func( core_t &, long, type1, type2 ) {} 455 456 SYMTAB_FUNC1( addId , const DeclWithType * ); 457 SYMTAB_FUNC1( addType , const NamedTypeDecl * ); 458 SYMTAB_FUNC1( addStruct , const StructDecl * ); 459 SYMTAB_FUNC1( addEnum , const EnumDecl * ); 460 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 461 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 462 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 463 464 // A few extra functions have more complicated behaviour, they are hand written 465 template<typename core_t> 466 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 467 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 468 for ( const auto & param : decl->params ) { 469 fwd->params.push_back( deepCopy( param.get() ) ); 470 } 471 core.symtab.addStruct( fwd ); 472 } 473 474 template<typename core_t> 475 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 476 477 template<typename core_t> 478 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 479 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name ); 480 for ( const auto & param : decl->params ) { 481 fwd->params.push_back( deepCopy( param.get() ) ); 482 } 483 core.symtab.addUnion( fwd ); 484 } 485 486 template<typename core_t> 487 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 488 489 template<typename core_t> 490 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 491 if ( ! core.symtab.lookupStruct( str ) ) { 492 core.symtab.addStruct( str ); 493 } 494 } 495 496 template<typename core_t> 497 static inline void addStruct( core_t &, long, const std::string & ) {} 498 499 template<typename core_t> 500 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 501 if ( ! core.symtab.lookupUnion( str ) ) { 502 core.symtab.addUnion( str ); 503 } 504 } 505 506 template<typename core_t> 507 static inline void addUnion( core_t &, long, const std::string & ) {} 508 509 #undef SYMTAB_FUNC1 510 #undef SYMTAB_FUNC2 511 } // namespace symtab 512 513 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 514 // Detect the presence of a member name `subs` and call all members appropriately 515 namespace forall { 516 // Some simple scoping rules 517 template<typename core_t> 518 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 519 -> decltype( core.subs, void() ) { 520 if ( ! type->forall.empty() ) core.subs.beginScope(); 521 } 522 523 template<typename core_t> 524 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 525 526 template<typename core_t> 527 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 528 -> decltype( core.subs, void() ) { 529 if ( ! type->forall.empty() ) { core.subs.endScope(); } 530 } 531 532 template<typename core_t> 533 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 534 535 // Replaces a TypeInstType's base TypeDecl according to the table 536 template<typename core_t> 537 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 538 -> decltype( core.subs, void() ) { 539 inst = ast::mutate_field( 540 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 541 } 542 543 template<typename core_t> 544 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 545 } // namespace forall 546 547 // For passes that need access to the global context. Searches `translationUnit` 548 namespace translation_unit { 549 template<typename core_t> 550 static inline auto get_cptr( core_t & core, int ) 551 -> decltype( &core.translationUnit ) { 552 return &core.translationUnit; 553 } 554 555 template<typename core_t> 556 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 557 return nullptr; 558 } 559 } 560 561 // For passes, usually utility passes, that have a result. 562 namespace result { 563 template<typename core_t> 564 static inline auto get( core_t & core, char ) -> decltype( core.result() ) { 510 565 return core.result(); 511 566 } 512 567 513 568 template<typename core_t> 514 static inline auto get _result( core_t & core, int ) -> decltype( core.result ) {569 static inline auto get( core_t & core, int ) -> decltype( core.result ) { 515 570 return core.result; 516 571 } 517 572 518 573 template<typename core_t> 519 static inline void get_result( core_t &, long ) {} 520 } // namespace __pass 521 } // namespace ast 574 static inline void get( core_t &, long ) {} 575 } 576 577 } // namespace ast::__pass 578 579 #undef __pedantic_pass_assertf 580 #undef __pedantic_pass_assert
Note:
See TracChangeset
for help on using the changeset viewer.