Ignore:
Timestamp:
May 10, 2019, 2:47:32 PM (4 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
arm-eh, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
37e3af4
Parents:
7f3f63c
Message:

More comments and naming conventions fix

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Pass.proto.hpp

    r7f3f63c r04124c4  
     1//
     2// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
     3//
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
     7// Pass.impl.hpp --
     8//
     9// Author           : Thierry Delisle
     10// Created On       : Thu May 09 15::37::05 2019
     11// Last Modified By :
     12// Last Modified On :
     13// Update Count     :
     14//
     15
    116#pragma once
    217// IWYU pragma: private, include "Pass.hpp"
    318
    419namespace ast {
    5         template<typename pass_type>
    6         class Pass;
    7 
    8         namespace __pass {
    9                 typedef std::function<void( void * )> cleanup_func_t;
    10                 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t;
    11 
    12 
    13                 // boolean reference that may be null
    14                 // either refers to a boolean value or is null and returns true
    15                 class bool_ref {
    16                 public:
    17                         bool_ref() = default;
    18                         ~bool_ref() = default;
    19 
    20                         operator bool() { return m_ref ? *m_ref : true; }
    21                         bool operator=( bool val ) { assert(m_ref); return *m_ref = val; }
    22 
    23                 private:
    24 
    25                         friend class visit_children_guard;
    26 
    27                         bool * set( bool * val ) {
    28                                 bool * prev = m_ref;
    29                                 m_ref = val;
    30                                 return prev;
     20template<typename pass_type>
     21class Pass;
     22
     23namespace __pass {
     24        typedef std::function<void( void * )> cleanup_func_t;
     25        typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t;
     26
     27
     28        // boolean reference that may be null
     29        // either refers to a boolean value or is null and returns true
     30        class bool_ref {
     31        public:
     32                bool_ref() = default;
     33                ~bool_ref() = default;
     34
     35                operator bool() { return m_ref ? *m_ref : true; }
     36                bool operator=( bool val ) { assert(m_ref); return *m_ref = val; }
     37
     38        private:
     39
     40                friend class visit_children_guard;
     41
     42                bool * set( bool * val ) {
     43                        bool * prev = m_ref;
     44                        m_ref = val;
     45                        return prev;
     46                }
     47
     48                bool * m_ref = nullptr;
     49        };
     50
     51        // Implementation of the guard value
     52        // Created inside the visit scope
     53        class guard_value {
     54        public:
     55                /// Push onto the cleanup
     56                guard_value( at_cleanup_t * at_cleanup ) {
     57                        if( at_cleanup ) {
     58                                *at_cleanup = [this]( cleanup_func_t && func, void* val ) {
     59                                        push( std::move( func ), val );
     60                                };
    3161                        }
    32 
    33                         bool * m_ref = nullptr;
     62                }
     63
     64                ~guard_value() {
     65                        while( !cleanups.empty() ) {
     66                                auto& cleanup = cleanups.top();
     67                                cleanup.func( cleanup.val );
     68                                cleanups.pop();
     69                        }
     70                }
     71
     72                void push( cleanup_func_t && func, void* val ) {
     73                        cleanups.emplace( std::move(func), val );
     74                }
     75
     76        private:
     77                struct cleanup_t {
     78                        cleanup_func_t func;
     79                        void * val;
     80
     81                        cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
    3482                };
    3583
    36                 // Implementation of the guard value
    37                 // Created inside the visit scope
    38                 class guard_value {
    39                 public:
    40                         guard_value( at_cleanup_t * at_cleanup ) {
    41                                 if( at_cleanup ) {
    42                                         *at_cleanup = [this]( cleanup_func_t && func, void* val ) {
    43                                                 push( std::move( func ), val );
    44                                         };
    45                                 }
     84                std::stack< cleanup_t > cleanups;
     85        };
     86
     87        // Guard structure implementation for whether or not children should be visited
     88        class visit_children_guard {
     89        public:
     90
     91                visit_children_guard( bool_ref * ref )
     92                        : m_val ( true )
     93                        , m_prev( ref ? ref->set( &m_val ) : nullptr )
     94                        , m_ref ( ref )
     95                {}
     96
     97                ~visit_children_guard() {
     98                        if( m_ref ) {
     99                                m_ref->set( m_prev );
    46100                        }
    47 
    48                         ~guard_value() {
    49                                 while( !cleanups.empty() ) {
    50                                         auto& cleanup = cleanups.top();
    51                                         cleanup.func( cleanup.val );
    52                                         cleanups.pop();
    53                                 }
    54                         }
    55 
    56                         void push( cleanup_func_t && func, void* val ) {
    57                                 cleanups.emplace( std::move(func), val );
    58                         }
    59 
    60                 private:
    61                         struct cleanup_t {
    62                                 cleanup_func_t func;
    63                                 void * val;
    64 
    65                                 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
    66                         };
    67 
    68                         std::stack< cleanup_t > cleanups;
    69                 };
    70 
    71                 // Guard structure implementation for whether or not children should be visited
    72                 class visit_children_guard {
    73                 public:
    74 
    75                         visit_children_guard( bool_ref * ref )
    76                                 : m_val ( true )
    77                                 , m_prev( ref ? ref->set( &m_val ) : nullptr )
    78                                 , m_ref ( ref )
    79                         {}
    80 
    81                         ~visit_children_guard() {
    82                                 if( m_ref ) {
    83                                         m_ref->set( m_prev );
    84                                 }
    85                         }
    86 
    87                         operator bool() { return m_val; }
    88 
    89                 private:
    90                         bool       m_val;
    91                         bool     * m_prev;
    92                         bool_ref * m_ref;
    93                 };
    94 
    95                 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    96                 // Deep magic (a.k.a template meta programming) to make the templated visitor work
    97                 // Basically the goal is to make 2 previsit
    98                 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
    99                 //     'pass.previsit( node )' that compiles will be used for that node for that type
    100                 //     This requires that this option only compile for passes that actually define an appropriate visit.
    101                 //     SFINAE will make sure the compilation errors in this function don't halt the build.
    102                 //     See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE
    103                 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing.
    104                 //     This is needed only to eliminate the need for passes to specify any kind of handlers.
    105                 //     The second implementation only works because it has a lower priority. This is due to the bogus last parameter.
    106                 //     The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0
    107                 //     the first implementation takes priority in regards to overloading.
    108                 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    109                 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    110                 template<typename pass_t, typename node_t>
    111                 static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
    112                         node = pass.previsit( node );
    113                         assert(node);
    114                 }
    115 
    116                 template<typename pass_t, typename node_t>
    117                 static inline auto previsit( pass_t &, const node_t *, long ) {}
    118 
    119                 // PostVisit : never mutates the passed pointer but may return a different node
    120                 template<typename pass_t, typename node_t>
    121                 static inline auto postvisit( pass_t & pass, const node_t * node, int ) -> decltype( pass.postvisit( node ), (const node_t *)nullptr ) {
    122                         return pass.postvisit( node );
    123                 }
    124 
    125                 template<typename pass_t, typename node_t>
    126                 static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
    127 
    128                 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    129                 // Deep magic (a.k.a template meta programming) continued
    130                 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit
    131                 // from in order to get extra functionallity for example
    132                 // class ErrorChecker : WithShortCircuiting { ... };
    133                 // Pass<ErrorChecker> checker;
    134                 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting
    135                 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched
    136                 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    137                 // For several accessories, the feature is enabled by detecting that a specific field is present
    138                 // Use a macro the encapsulate the logic of detecting a particular field
    139                 // The type is not strictly enforced but does match the accessory
    140                 #define FIELD_PTR( name, default_type ) \
    141                 template< typename pass_t > \
    142                 static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
     101                }
     102
     103                operator bool() { return m_val; }
     104
     105        private:
     106                bool       m_val;
     107                bool     * m_prev;
     108                bool_ref * m_ref;
     109        };
     110
     111        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     112        // Deep magic (a.k.a template meta programming) to make the templated visitor work
     113        // Basically the goal is to make 2 previsit
     114        // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
     115        //     'pass.previsit( node )' that compiles will be used for that node for that type
     116        //     This requires that this option only compile for passes that actually define an appropriate visit.
     117        //     SFINAE will make sure the compilation errors in this function don't halt the build.
     118        //     See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE
     119        // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing.
     120        //     This is needed only to eliminate the need for passes to specify any kind of handlers.
     121        //     The second implementation only works because it has a lower priority. This is due to the bogus last parameter.
     122        //     The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0
     123        //     the first implementation takes priority in regards to overloading.
     124        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     125        // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
     126        template<typename pass_t, typename node_t>
     127        static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
     128                node = pass.previsit( node );
     129                assert(node);
     130        }
     131
     132        template<typename pass_t, typename node_t>
     133        static inline auto previsit( pass_t &, const node_t *, long ) {}
     134
     135        // PostVisit : never mutates the passed pointer but may return a different node
     136        template<typename pass_t, typename node_t>
     137        static inline auto postvisit( pass_t & pass, const node_t * node, int ) -> decltype( pass.postvisit( node ), (const node_t *)nullptr ) {
     138                return pass.postvisit( node );
     139        }
     140
     141        template<typename pass_t, typename node_t>
     142        static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
     143
     144        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     145        // Deep magic (a.k.a template meta programming) continued
     146        // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit
     147        // from in order to get extra functionallity for example
     148        // class ErrorChecker : WithShortCircuiting { ... };
     149        // Pass<ErrorChecker> checker;
     150        // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting
     151        // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched
     152        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     153        // For several accessories, the feature is enabled by detecting that a specific field is present
     154        // Use a macro the encapsulate the logic of detecting a particular field
     155        // The type is not strictly enforced but does match the accessory
     156        #define FIELD_PTR( name, default_type ) \
     157        template< typename pass_t > \
     158        static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
     159        \
     160        template< typename pass_t > \
     161        static inline default_type * name( pass_t &, long ) { return nullptr; }
     162
     163        // List of fields and their expected types
     164        FIELD_PTR( env, const ast::TypeSubstitution )
     165        FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
     166        FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
     167        FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
     168        FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
     169        FIELD_PTR( visit_children, __pass::bool_ref )
     170        FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
     171        FIELD_PTR( visitor, ast::Pass<pass_t> * const )
     172
     173        // Remove the macro to make sure we don't clash
     174        #undef FIELD_PTR
     175
     176        // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     177        // All passes which have such functions are assumed desire this behaviour
     178        // detect it using the same strategy
     179        namespace scope {
     180                template<typename pass_t>
     181                static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
     182                        pass.beginScope();
     183                }
     184
     185                template<typename pass_t>
     186                static inline void enter( pass_t &, long ) {}
     187
     188                template<typename pass_t>
     189                static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
     190                        pass.endScope();
     191                }
     192
     193                template<typename pass_t>
     194                static inline void leave( pass_t &, long ) {}
     195        };
     196
     197        // Finally certain pass desire an up to date indexer automatically
     198        // detect the presence of a member name indexer and call all the members appropriately
     199        namespace indexer {
     200                // Some simple scoping rules
     201                template<typename pass_t>
     202                static inline auto enter( pass_t & pass, int ) -> decltype( pass.indexer.enterScope(), void() ) {
     203                        pass.indexer.enterScope();
     204                }
     205
     206                template<typename pass_t>
     207                static inline auto enter( pass_t &, long ) {}
     208
     209                template<typename pass_t>
     210                static inline auto leave( pass_t & pass, int ) -> decltype( pass.indexer.leaveScope(), void() ) {
     211                        pass.indexer.leaveScope();
     212                }
     213
     214                template<typename pass_t>
     215                static inline auto leave( pass_t &, long ) {}
     216
     217                // The indexer has 2 kind of functions mostly, 1 argument and 2 arguments
     218                // Create macro to condense these common patterns
     219                #define INDEXER_FUNC1( func, type ) \
     220                template<typename pass_t> \
     221                static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.indexer.func( arg ), void() ) {\
     222                        pass.indexer.func( arg ); \
     223                } \
    143224                \
    144                 template< typename pass_t > \
    145                 static inline default_type * name( pass_t &, long ) { return nullptr; }
    146 
    147                 // List of fields and their expected types
    148                 FIELD_PTR( env, const ast::TypeSubstitution )
    149                 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
    150                 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
    151                 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
    152                 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
    153                 FIELD_PTR( visit_children, __pass::bool_ref )
    154                 FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    155                 FIELD_PTR( visitor, ast::Pass<pass_t> * const )
    156 
    157                 // Remove the macro to make sure we don't clash
    158                 #undef FIELD_PTR
    159 
    160                 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
    161                 // All passes which have such functions are assumed desire this behaviour
    162                 // detect it using the same strategy
    163                 namespace scope {
    164                         template<typename pass_t>
    165                         static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
    166                                 pass.beginScope();
    167                         }
    168 
    169                         template<typename pass_t>
    170                         static inline void enter( pass_t &, long ) {}
    171 
    172                         template<typename pass_t>
    173                         static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
    174                                 pass.endScope();
    175                         }
    176 
    177                         template<typename pass_t>
    178                         static inline void leave( pass_t &, long ) {}
    179                 };
    180 
    181                 // Finally certain pass desire an up to date indexer automatically
    182                 // detect the presence of a member name indexer and call all the members appropriately
    183                 namespace indexer {
    184                         // Some simple scoping rules
    185                         template<typename pass_t>
    186                         static inline auto enter( pass_t & pass, int ) -> decltype( pass.indexer.enterScope(), void() ) {
    187                                 pass.indexer.enterScope();
    188                         }
    189 
    190                         template<typename pass_t>
    191                         static inline auto enter( pass_t &, long ) {}
    192 
    193                         template<typename pass_t>
    194                         static inline auto leave( pass_t & pass, int ) -> decltype( pass.indexer.leaveScope(), void() ) {
    195                                 pass.indexer.leaveScope();
    196                         }
    197 
    198                         template<typename pass_t>
    199                         static inline auto leave( pass_t &, long ) {}
    200 
    201                         // The indexer has 2 kind of functions mostly, 1 argument and 2 arguments
    202                         // Create macro to condense these common patterns
    203                         #define INDEXER_FUNC1( func, type ) \
    204                         template<typename pass_t> \
    205                         static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.indexer.func( arg ), void() ) {\
    206                                 pass.indexer.func( arg ); \
    207                         } \
     225                template<typename pass_t> \
     226                static inline void func( pass_t &, long, type ) {}
     227
     228                #define INDEXER_FUNC2( func, type1, type2 ) \
     229                template<typename pass_t> \
     230                static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.indexer.func( arg1, arg2 ), void () ) {\
     231                        pass.indexer.func( arg1, arg2 ); \
     232                } \
    208233                        \
    209                         template<typename pass_t> \
    210                         static inline void func( pass_t &, long, type ) {}
    211 
    212                         #define INDEXER_FUNC2( func, type1, type2 ) \
    213                         template<typename pass_t> \
    214                         static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.indexer.func( arg1, arg2 ), void () ) {\
    215                                 pass.indexer.func( arg1, arg2 ); \
    216                         } \
    217                          \
    218                         template<typename pass_t> \
    219                         static inline void func( pass_t &, long, type1, type2 ) {}
    220 
    221                         INDEXER_FUNC1( addId     , DeclarationWithType *       );
    222                         INDEXER_FUNC1( addType   , NamedTypeDecl *             );
    223                         INDEXER_FUNC1( addStruct , StructDecl *                );
    224                         INDEXER_FUNC1( addEnum   , EnumDecl *                  );
    225                         INDEXER_FUNC1( addUnion  , UnionDecl *                 );
    226                         INDEXER_FUNC1( addTrait  , TraitDecl *                 );
    227                         INDEXER_FUNC2( addWith   , std::list< Expression * > &, BaseSyntaxNode * );
    228 
    229                         // A few extra functions have more complicated behaviour, they are hand written
    230                         template<typename pass_t>
    231                         static inline auto addStructFwd( pass_t & pass, int, ast::StructDecl * decl ) -> decltype( pass.indexer.addStruct( decl ), void() ) {
    232                                 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    233                                 fwd->parameters = decl->parameters;
    234                                 pass.indexer.addStruct( fwd );
    235                         }
    236 
    237                         template<typename pass_t>
    238                         static inline void addStructFwd( pass_t &, long, ast::StructDecl * ) {}
    239 
    240                         template<typename pass_t>
    241                         static inline auto addUnionFwd( pass_t & pass, int, ast::UnionDecl * decl ) -> decltype( pass.indexer.addUnion( decl ), void() ) {
    242                                 UnionDecl * fwd = new UnionDecl( decl->name );
    243                                 fwd->parameters = decl->parameters;
    244                                 pass.indexer.addUnion( fwd );
    245                         }
    246 
    247                         template<typename pass_t>
    248                         static inline void addUnionFwd( pass_t &, long, ast::UnionDecl * ) {}
    249 
    250                         template<typename pass_t>
    251                         static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addStruct( str ), void() ) {
    252                                 if ( ! pass.indexer.lookupStruct( str ) ) {
    253                                         pass.indexer.addStruct( str );
    254                                 }
    255                         }
    256 
    257                         template<typename pass_t>
    258                         static inline void addStruct( pass_t &, long, const std::string & ) {}
    259 
    260                         template<typename pass_t>
    261                         static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addUnion( str ), void() ) {
    262                                 if ( ! pass.indexer.lookupUnion( str ) ) {
    263                                         pass.indexer.addUnion( str );
    264                                 }
    265                         }
    266 
    267                         template<typename pass_t>
    268                         static inline void addUnion( pass_t &, long, const std::string & ) {}
    269 
    270                         #undef INDEXER_FUNC1
    271                         #undef INDEXER_FUNC2
    272                 };
     234                template<typename pass_t> \
     235                static inline void func( pass_t &, long, type1, type2 ) {}
     236
     237                INDEXER_FUNC1( addId     , DeclWithType *  );
     238                INDEXER_FUNC1( addType   , NamedTypeDecl * );
     239                INDEXER_FUNC1( addStruct , StructDecl *    );
     240                INDEXER_FUNC1( addEnum   , EnumDecl *      );
     241                INDEXER_FUNC1( addUnion  , UnionDecl *     );
     242                INDEXER_FUNC1( addTrait  , TraitDecl *     );
     243                INDEXER_FUNC2( addWith   , std::list< Expression * > &, Node * );
     244
     245                // A few extra functions have more complicated behaviour, they are hand written
     246                // template<typename pass_t>
     247                // static inline auto addStructFwd( pass_t & pass, int, ast::StructDecl * decl ) -> decltype( pass.indexer.addStruct( decl ), void() ) {
     248                //      ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
     249                //      fwd->parameters = decl->parameters;
     250                //      pass.indexer.addStruct( fwd );
     251                // }
     252
     253                // template<typename pass_t>
     254                // static inline void addStructFwd( pass_t &, long, ast::StructDecl * ) {}
     255
     256                // template<typename pass_t>
     257                // static inline auto addUnionFwd( pass_t & pass, int, ast::UnionDecl * decl ) -> decltype( pass.indexer.addUnion( decl ), void() ) {
     258                //      UnionDecl * fwd = new UnionDecl( decl->name );
     259                //      fwd->parameters = decl->parameters;
     260                //      pass.indexer.addUnion( fwd );
     261                // }
     262
     263                // template<typename pass_t>
     264                // static inline void addUnionFwd( pass_t &, long, ast::UnionDecl * ) {}
     265
     266                // template<typename pass_t>
     267                // static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addStruct( str ), void() ) {
     268                //      if ( ! pass.indexer.lookupStruct( str ) ) {
     269                //              pass.indexer.addStruct( str );
     270                //      }
     271                // }
     272
     273                // template<typename pass_t>
     274                // static inline void addStruct( pass_t &, long, const std::string & ) {}
     275
     276                // template<typename pass_t>
     277                // static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addUnion( str ), void() ) {
     278                //      if ( ! pass.indexer.lookupUnion( str ) ) {
     279                //              pass.indexer.addUnion( str );
     280                //      }
     281                // }
     282
     283                // template<typename pass_t>
     284                // static inline void addUnion( pass_t &, long, const std::string & ) {}
     285
     286                #undef INDEXER_FUNC1
     287                #undef INDEXER_FUNC2
    273288        };
    274289};
     290};
Note: See TracChangeset for help on using the changeset viewer.