Changeset 768b3b4f


Ignore:
Timestamp:
May 13, 2019, 2:01:20 PM (2 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
arm-eh, cleanup-dtors, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr
Children:
712348a, 9b81fed
Parents:
b78129a (diff), 336d0b3 (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.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
1 added
20 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/vtable.md

    rb78129a r768b3b4f  
    88
    99The basic concept of a virtual table (vtable) is the same here as in most
    10 other languages. They will mostly contain function pointers although they
    11 should be able to store anything that goes into a trait.
    12 
    13 I also include notes on a sample implementation, which primarly exists to show
    14 there is a resonable implementation. The code samples for that are in a slight
    15 psudo-code to help avoid name mangling and keeps some CFA features while they
    16 would actually be writen in C.
     10other languages that use them. They will mostly contain function pointers
     11although they should be able to store anything that goes into a trait.
     12
     13I also include notes on a sample implementation, which primarily exists to show
     14there is a reasonable implementation. The code samples for that are in a slight
     15pseudo-code to help avoid name mangling and keeps some CFA features while they
     16would actually be written in C.
    1717
    1818Trait Instances
     
    2020
    2121Currently traits are completely abstract. Data types might implement a trait
    22 but traits are not themselves data types. This will change that and allow
    23 instances of traits to be created from instances of data types that implement
    24 the trait.
     22but traits are not themselves data types. Which is to say you cannot have an
     23instance of a trait. This proposal will change that and allow instances of
     24traits to be created from instances of data types that implement the trait.
     25
     26For example:
    2527
    2628    trait combiner(otype T) {
    27                 void combine(T&, int);
    28         };
     29        void combine(T&, int);
     30    };
    2931
    3032    struct summation {
    31                 int sum;
    32         };
    33 
    34         void ?{}( struct summation & this ) {
    35                 this.sum = 0;
    36         }
     33        int sum;
     34    };
     35
     36    void ?{}( struct summation & this ) {
     37        this.sum = 0;
     38    }
    3739
    3840    void combine( struct summation & this, int num ) {
    39                 this.sum = this.sum + num;
    40         }
    41 
    42         trait combiner obj = struct summation{};
    43         combine(obj, 5);
     41        this.sum = this.sum + num;
     42    }
     43
     44    trait combiner obj = struct summation{};
     45    combine(obj, 5);
    4446
    4547As with `struct` (and `union` and `enum`), `trait` might be optional when
     
    4951For traits to be used this way they should meet two requirements. First they
    5052should only have a single polymorphic type and each assertion should use that
    51 type once as a parameter. Extentions may later loosen these requirements.
    52 
    53 If a trait object is used it should generate a series of implicate functions
    54 each of which implements one of the functions required by the trait. So for
    55 combiner there is an implicate:
    56 
    57     void combine(trait combiner & this, int);
    58 
    59 This function is the one actually called at the end
     53type once as a parameter. Extensions may later loosen these requirements.
     54
     55Also note this applies to the final expanded list of assertions. Consider:
     56
     57    trait foo(otype T, otype U) {
     58        ... functions that use T once ...
     59    }
     60
     61    trait bar(otype S | foo(S, char)) {
     62        ... functions that use S once ...
     63    }
     64
     65In this example `bar` may be used as a type but `foo` may not.
     66
     67When a trait is used as a type it creates a generic object which combines
     68the base structure (an instance of `summation` in this case) and the vtable,
     69which is currently created and provided by a hidden mechanism.
     70
     71The generic object type for each trait also implements that trait. This is
     72actually the only means by which it can be used. The type of these functions
     73look something like this:
     74
     75    void combine(trait combiner & this, int num);
    6076
    6177The main use case for trait objects is that they can be stored. They can be
    62 passed into functions, but using the trait directly is prefred in this case.
     78passed into functions, but using the trait directly is preferred in this case.
    6379
    6480    trait drawable(otype T) {
     
    7894    }
    7995
    80 Currently these traits are limited to 1 trait parameter and functions should
    81 have exactly 1 parameter. We cannot abstract away pairs of types and still
    82 pass them into normal functions, which take them seperately.
    83 
    84 The second is required the because we need to get the vtable from somewhere.
    85 If there are 0 trait objects than no vtable is avalible, if we have more than
    86 1 than the vtables give conflicting answers on what underlying function to
    87 call. And even then the underlying type assumes a concrete type.
    88 
    89 This loop can sort of be broken by using the trait object directly in the
    90 signature. This has well defined meaning, but might not be useful.
     96The trait types can also be used in the types of assertions on traits as well.
     97In this usage they passed as the underlying object and vtable pair as they
     98are stored. The trait types can also be used in that trait's definition, which
     99means you can pass two instances of a trait to a single function. However the
     100look-up of the one that is not used to look up any functions, until another
     101function that uses that object in the generic/look-up location is called.
    91102
    92103    trait example(otype T) {
    93104        bool test(T & this, trait example & that);
    94105    }
     106
     107### Explanation Of Restrictions
     108
     109The two restrictions on traits that can be used as trait objects are:
     110
     1111.  Only one generic parameter may be defined in the trait's header.
     1122.  Each function assertion must have one parameter with the type of the
     113    generic parameter. They may or may not return a value of that type.
     114
     115Elsewhere in this proposal I suggest ways to broaden these requirements.
     116A simple example would be if a trait meets requirement 1 but not 2, then
     117the assertions that do not satisfy the exactly one parameter requirement can
     118be ignored.
     119
     120However I would like to talk about why these two rules are in place in the
     121first place and the problems that any exceptions to these rules must avoid.
     122
     123The problems appear when the dispatcher function which operates on the
     124generic object.
     125
     126    trait combiner(otype T, otype U) {
     127        void combine(T&, U);
     128    }
     129
     130This one is so strange I don't have proper syntax for it but let us say that
     131the concrete dispatcher would be typed as
     132`void combine(combiner(T) &, combiner(U));`. Does the function that combine
     133the two underlying types exist to dispatch too?
     134
     135Maybe not. If `combiner(T)` works with ints and `combiner(U)` is a char then
     136they could not be. It would have to enforce that all pairs of any types
     137that are wrapped in this way. Which would pretty much destroy any chance of
     138separate compilation.
     139
     140Even then it would be more expensive as the wrappers would have to carry ids
     141that you use to look up on an <number of types>+1 dimensional table.
     142
     143The second restriction has a similar issue but makes a bit more sense to
     144write out.
     145
     146    trait Series(otype T) {
     147        ... size, iterators, getters ...
     148        T join(T const &, T const &);
     149    }
     150
     151With the dispatcher typed as:
     152
     153    Series join(Series const &, Series const &);
     154
     155Because these instances are generic and hide the underlying implementation we
     156do not know what that implementation is. Unfortunately this also means the
     157implementation for the two parameters might not be the same. Once we have
     158two different types involved this devolves into the first case.
     159
     160We could check at run-time that the have the same underlying type, but this
     161would likely time and space overhead and there is no clear recovery path.
    95162
    96163#### Sample Implementation
     
    116183
    117184There may have to be special cases for things like copy construction, that
    118 might require a more sigificant wrapper. On the other hand moving could be
     185might require a more significant wrapper. On the other hand moving could be
    119186implemented by moving the pointers without any need to refer to the base
    120187object.
    121188
    122 ### Extention: Multiple Trait Parameters
    123 Currently, this gives traits two independent uses. They use the same syntax,
    124 except for limits boxable traits have, and yet don't really mix. The most
    125 natural way to do this is to allow trait instances to pick one parameter
    126 that they are generic over, the others they choose types to implement.
    127 
    128 The two ways to do the selection, the first is do it at the trait definition.
    129 Each trait picks out a single parameter which it can box (here the `virtual`
    130 qualifier). When you create an instance of a trait object you provide
    131 arguments like for a generic structure, but skip over the marked parameter.
    132 
    133     trait combiner(virtual otype T, otype Combined) {
    134         void combine(T &, Combined &);
    135     }
    136 
    137     trait combiner(int) int_combiner;
    138 
    139 The second is to do it at the instaniation point. A placeholder (here the
    140 keyword `virtual`) is used to explicately skip over the parameter that will be
    141 abstracted away, with the same rules as above if it was the marked parameter.
    142 
    143     trait combiner(otype T, otype Combined) {
    144         void combine(T &, Combined &);
    145     };
    146 
    147     trait combiner(virtual, int) int_combiner;
    148 
    149 Using both (first to set the default, second as a local override) would also
    150 work, although might be exessively complicated.
    151 
    152 This is useful in cases where you want to use a generic type, but leave part
    153 of it open and store partially generic result. As a simple example
    154 
    155     trait folder(otype T, otype In, otype Out) {
    156         void fold(T & this, In);
    157         Out fold_result(T & this);
    158     }
    159 
    160 Which allows you to fold values without putting them in a container. If they
    161 are already in a container this is exessive, but if they are generated over
    162 time this gives you a simple interface. This could for instance be used in
    163 a profile, where T changes for each profiling statistic and you can plug in
    164 multiple profilers for any run by adding them to an array.
     189### Extension: Multiple Trait Parameters
     190The base proposal in effect creates another use for the trait syntax that is
     191related to the ones currently in the language but is also separate from them.
     192The current uses generic functions and generic types, this new use could be
     193described as generic objects.
     194
     195A generic object is of a concrete type and has concrete functions that work on
     196it. It is generic in that it is a wrapper for an unknown type. Traits serve
     197a similar role here as in generic functions as they limit what the function
     198can be generic over.
     199
     200This combines the use allowing to have a generic type that is a generic
     201object. All but one of the trait's parameters is given a concrete type,
     202conceptually currying the trait to create a trait with on generic parameter
     203that fits the original restrictions. The resulting concrete generic object
     204type is different with each set of provided parameters and their values.
     205
     206Then it just becomes a question of where this is done. Again both examples use
     207a basic syntax to show the idea.
     208
     209    trait iterator(virtual otype T, otype Item) {
     210        bool has_next(T const &);
     211        Item get_next(T const *);
     212    }
     213
     214    iterator(int) int_it = begin(container_of_ints);
     215
     216The first option is to do it at the definition of the trait. One parameter
     217is selected (here with the `virtual` keyword, but other rules like "the first"
     218could also be used) and when an instance of the trait is created all the
     219other parameters must be provided.
     220
     221    trait iterator(otype T, otype Item) {
     222        bool has_next(T const &);
     223        Item get_next(T const *);
     224    }
     225
     226    iterator(virtual, int) int_it = begin(container_of_ints);
     227
     228The second option is to skip a parameter as part of the type instance
     229definition. One parameter is explicitly skipped (again with the `virtual`
     230keyword) and the others have concrete types. The skipped one is the one we
     231are generic on.
     232
     233Incidentally in both examples `container_of_ints` may itself be a generic
     234object and `begin` returns a generic iterator with unknown implementation.
     235
     236These options are not exclusive. Defining a default on the trait allows for
     237an object to be created as in the first example. However, whether the
     238default is provided or not, the second syntax can be used to pick a
     239parameter on instantiation.
    165240
    166241Hierarchy
    167242---------
    168243
    169 Virtual tables by them selves are not quite enough to implement the planned
    170 hierarchy system. An addition of type ids, implemented as pointers which
    171 point to your parent's type id, is required to actually create the shape of
    172 the hierarchy. However vtables would allow behaviour to be carried with the
    173 tree.
    174 
    175 The hierarchy would be a tree of types, of traits and structs. Currently we do
    176 not support structural extension, so traits form the internal nodes and
    177 structures the leaf nodes.
    178 
    179 The syntax is undecided but it will include a clause like `virtual (PARENT)`
    180 on trait and struct definitions. It marks out all types in a hierarchy.
    181 PARENT may be omitted, if it is this type is the root of a hierarchy. Otherwise
    182 it is the name of the type that is this type's parent in the hierarchy.
    183 
    184 Traits define a trait instance type that implements all assertions in this
    185 trait and its parents up until the root of the hierarchy. Each trait then
    186 defines a vtable type. Structures will also have a vtable type but it should
    187 be the same as their parent's.
    188 
    189 Trait objects within the tree can be statically cast to a parent type. Casts
    190 from a parent type to a child type are conditional, they check to make sure
    191 the underlying instance is an instance of the child type, or an instance of
    192 one of its children. The type then is recoverable at run-time.
    193 
    194 As with regular trait objects, calling a function on a trait object will cause
    195 a look-up on the the virtual table. The casting rules make sure anything that
    196 can be cast to a trait type will have all the function implementations for
    197 that trait.
    198 
    199 Converting from a concrete type (structures at the edge of the hierarchy) to
    200 an abstract type works the same as with normal trait objects, the underlying
    201 object is packaged with a virtual table pointer. Converting back to an abstract
    202 type requires confirming the underlying type matches, but then simply extracts
    203 the pointer to it.
    204 
    205 Exception Example:
     244We would also like to implement hierarchical relations between types.
     245
     246    AstNode
     247    |-ParseNode
     248    | |-Declaration
     249    | | |-DeclarationWithType
     250    | | |-StructureDeclaration
     251    | |-Statement
     252    | | |-CompoundStatement
     253    | |-Expression
     254    |-Type
     255
     256Virtual tables by themselves are not quite enough to implement this system.
     257A vtable is just a list of functions and there is no way to check at run-time
     258what these functions, we carry that knowledge with the table.
     259
     260This proposal adds type ids to check for position in the hierarchy and an
     261explicate syntax for establishing a hierarchical relation between traits and
     262their implementing types. The ids should uniquely identify each type and
     263allow retrieval of the type's parent if one exists. By recursion this allows
     264the ancestor relation between any two hierarchical types can be checked.
     265
     266The hierarchy is created with traits as the internal nodes and structures
     267as the leaf nodes. The structures may be used normally and the traits can
     268be used to create generic objects as in the first section (the same
     269restrictions apply). However these type objects store their type id which can
     270be recovered to figure out which type they are or at least check to see if
     271they fall into a given sub-tree at run-time.
     272
     273Here is an example of part of a hierarchy. The `virtual(PARENT)` syntax is
     274just an example. But when used it give the name of the parent type or if
     275empty it shows that this type is the root of its hierarchy.
    206276(Also I'm not sure where I got these casing rules.)
    207 
    208     trait exception(otype T) virtual() {
    209         char const * what(T & this);
    210     }
    211 
    212     trait io_error(otype T) virtual(exception) {
    213         FILE * which_file(T & this);
    214     }
    215 
    216     struct eof_error(otype T) virtual(io_error) {
    217         FILE * file;
    218     }
    219 
    220     char const * what(eof_error &) {
    221         return "Tried to read from an empty file.";
    222     }
    223 
    224     FILE * which_file(eof_error & this) {
    225         return eof_error.file;
    226     }
    227 
    228 Ast Example:
    229277
    230278    trait ast_node(otype T) virtual() {
     
    267315    }
    268316
     317### Extension: Structural Inheritance
     318An extension would be allow structures to be used as internal nodes on the
     319inheritance tree. Its child types would have to implement the same fields.
     320
     321The weaker restriction would be to convert the fields into field assertions
     322(Not implemented yet: `U T.x` means there is a field of type you on the type
     323T. Offset unknown and passed in/stored with function pointers.)
     324A concrete child would have to declare the same set of fields with the same
     325types. This is of a more functional style.
     326
     327The stronger restriction is that the fields of the parent are a prefix of the
     328child's fields. Possibly automatically inserted. This the imperative view and
     329may also have less overhead.
     330
     331### Extension: Unions and Enumerations
     332Currently there is no reason unions and enumerations, in the cases they
     333do implement the trait, could not be in the hierarchy as leaf nodes.
     334
     335It does not work with structural induction, but that could just be a compile
     336time check that all ancestors are traits or do not add field assertions.
     337
    269338#### Sample Implementation
    270339The type id may be as little as:
     
    275344
    276345Some linker magic would have to be used to ensure exactly one copy of each
    277 structure for each type exists in memory. There seem to be spectial once
     346structure for each type exists in memory. There seem to be special once
    278347sections that support this and it should be easier than generating unique
    279348ids across compilation units.
     
    300369
    301370### Virtual Casts
    302 To convert from a pointer to a type higher on the hierarchy to one lower on
    303 the hierarchy a check is used to make sure that the underlying type is also
    304 of that lower type.
    305 
    306 The proposed syntax for this is:
     371The generic objects may be cast up and down the hierarchy.
     372
     373Casting to an ancestor type always succeeds. From one generic type to another
     374is just a reinterpretation and could be implicate. Wrapping and unwrapping
     375a concrete type will probably use the same syntax as in the first section.
     376
     377Casting from an ancestor to a descendent requires a check. The underlying
     378type may or may not belong to the sub-tree headed by that descendent. For this
     379we introduce a new cast operator, which returns the pointer unchanged if the
     380check succeeds and null otherwise.
    307381
    308382    trait SubType * new_value = (virtual trait SubType *)super_type;
    309383
    310 It will return the same pointer if it does point to the subtype and null if
    311 it does not, doing the check and conversion in one operation.
    312 
    313 ### Inline vtables
     384For the following example I am using the as of yet finished exception system.
     385
     386    trait exception(otype T) virtual() {
     387        char const * what(T & this);
     388    }
     389
     390    trait io_error(otype T) virtual(exception) {
     391        FILE * which_file(T & this);
     392    }
     393
     394    struct eof_error(otype T) virtual(io_error) {
     395        FILE * file;
     396    }
     397
     398    char const * what(eof_error &) {
     399        return "Tried to read from an empty file.";
     400    }
     401
     402    FILE * which_file(eof_error & this) {
     403        return eof_error.file;
     404    }
     405
     406    bool handleIoError(exception * exc) {
     407        io_error * error = (virtual io_error *)exc;
     408        if (NULL == error) {
     409            return false;
     410        }
     411        ...
     412        return true;
     413    }
     414
     415### Extension: Implicate Virtual Cast Target
     416This is a small extension, even in the example above `io_error *` is repeated
     417in the cast and the variable being assigned to. Using return type inference
     418would allow the second type to be skipped in cases it is clear what type is
     419being checked against.
     420
     421The line then becomes:
     422
     423    io_error * error = (virtual)exc;
     424
     425### Extension: Inline vtables
    314426Since the structures here are usually made to be turned into trait objects
    315 it might be worth it to have fields on them to store the virtual table
     427it might be worth it to have fields in them to store the virtual table
    316428pointer. This would have to be declared on the trait as an assertion (example:
    317429`vtable;` or `T.vtable;`), but if it is the trait object could be a single
     
    320432There are also three options for where the pointer to the vtable. It could be
    321433anywhere, a fixed location for each trait or always at the front. For the per-
    322 trait solution an extention to specify what it is (example `vtable[0];`) which
     434trait solution an extension to specify what it is (example `vtable[0];`) which
    323435could also be used to combine it with others. So these options can be combined
    324436to allow access to all three options.
     
    344456the type declaration, including the functions that satisfy the trait, are
    345457all defined. Currently there are many points where this can happen, not all
    346 of them will have the same definitions and no way to select one over the
    347 other.
     458of them have the same definitions and no way to select one over the other.
    348459
    349460Some syntax would have to be added to specify the resolution point. To ensure
     
    395506
    396507These could also be placed inside functions. In which case both the name and
    397 the default keyword might be optional. If the name is ommited in an assignment
    398 the closest vtable is choosen (returning to the global default rule if no
    399 approprate local vtable is in scope).
     508the default keyword might be optional. If the name is omitted in an assignment
     509the closest vtable is chosen (returning to the global default rule if no
     510appropriate local vtable is in scope).
    400511
    401512### Site Based Resolution:
  • src/AST/Attribute.hpp

    rb78129a r768b3b4f  
    4747};
    4848
     49
     50
     51//=================================================================================================
     52/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
     53/// remove only if there is a better solution
     54/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
     55/// forward declarations
     56inline void increment( const class Attribute * node, Node::ref_type ref ) { node->increment( ref ); }
     57inline void decrement( const class Attribute * node, Node::ref_type ref ) { node->decrement( ref ); }
    4958}
    5059
  • src/AST/Bitfield.hpp

    rb78129a r768b3b4f  
    2222/// does not allow it. Requires type to have `unsigned val` field
    2323/// @param BFType  Name of containing type
    24 #define MakeBitfield( BFType )                                         \
    25         constexpr BFType() : val( 0 ) {}                                   \
    26         constexpr BFType( unsigned int v ) : val( v ) {}                   \
    27         bool operator[]( unsigned int i ) const { return val & (1 << i); } \
    28         bool any() const { return val != 0; }                              \
    29         void reset() { val = 0; }                                          \
    30         int ffs() { return ::ffs( val ) - 1; }                             \
    31         BFType operator&=( BFType other ) {                                \
    32                 val &= other.val; return *this;                                \
    33         }                                                                  \
    34         BFType operator&( BFType other ) const {                           \
    35                 BFType q = other;                                              \
    36                 q &= *this;                                                    \
    37                 return q;                                                      \
    38         }                                                                  \
    39         BFType operator|=( BFType other ) {                                \
    40                 val |= other.val; return *this;                                \
    41         }                                                                  \
    42         BFType operator|( BFType other ) const {                           \
    43                 BFType q = other;                                              \
    44                 q |= *this;                                                    \
    45                 return q;                                                      \
    46         }                                                                  \
    47         BFType operator-=( BFType other ) {                                \
    48                 val &= ~other.val; return *this;                               \
     24template<typename T>
     25struct bitfield : public T {
     26        static_assert(sizeof(T) == sizeof(unsigned int), "Type has incorrect size");
     27        using T::val;
     28        using val_t = decltype(val);
     29
     30        constexpr bitfield() : T( 0 ) {}
     31        constexpr bitfield( val_t v ) : T( v ) {}
     32
     33        bool operator[]( val_t i ) const { return val & (1 << i); }
     34        bool any() const { return val != 0; }
     35        void reset() { val = 0; }
     36        int ffs() { return ::ffs( val ) - 1; }
     37
     38        bitfield operator&=( bitfield other ) {
     39                val &= other.val; return *this;
    4940        }
     41        bitfield operator&( bitfield other ) const {
     42                bitfield q = other;
     43                q &= *this;
     44                return q;
     45        }
     46        bitfield operator|=( bitfield other ) {
     47                val |= other.val; return *this;
     48        }
     49        bitfield operator|( bitfield other ) const {
     50                bitfield q = other;
     51                q |= *this;
     52                return q;
     53        }
     54        bitfield operator-=( bitfield other ) {
     55                val &= ~other.val; return *this;
     56        }
     57};
    5058
    5159/// Adds default printing operator to a bitfield type.
    5260/// Include in definition to add print function, requires other bitfield operators.
    5361/// @param N  Number of bits in bitfield
    54 #define MakeBitfieldPrint( N )                                         \
    55         static const char* Names[];                                        \
    56         void print( std::ostream & os ) const {                            \
    57                 if ( (*this).any() ) {                                         \
    58                         for ( unsigned int i = 0; i < N; i += 1 ) {                \
    59                                 if ( (*this)[i] ) {                                    \
    60                                         os << Names[i] << ' ';                             \
    61                                 }                                                      \
    62                         }                                                          \
    63                 }                                                              \
     62#define MakeBitfieldPrint( N ) \
     63        static const char* Names[]; \
     64 \
     65        void print( std::ostream & os ) const { \
     66                if ( (*this).any() ) { \
     67                        for ( unsigned int i = 0; i < N; i += 1 ) { \
     68                                if ( (*this)[i] ) { \
     69                                        os << Names[i] << ' '; \
     70                                } \
     71                        } \
     72                } \
    6473        }
    6574
  • src/AST/Decl.hpp

    rb78129a r768b3b4f  
    122122        std::vector<ptr<DeclWithType>> assertions;
    123123
    124         NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 
     124        NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
    125125                Type* b, Linkage::Spec spec = Linkage::Cforall )
    126126        : Decl( loc, name, storage, spec ), base( b ), parameters(), assertions() {}
     
    149149                Data( TypeDecl* d ) : kind( d->kind ), isComplete( d->sized ) {}
    150150                Data( Kind k, bool c ) : kind( k ), isComplete( c ) {}
    151                 Data( const Data& d1, const Data& d2 ) 
     151                Data( const Data& d1, const Data& d2 )
    152152                : kind( d1.kind ), isComplete( d1.isComplete || d2.isComplete ) {}
    153153
     
    158158        };
    159159
    160         TypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, Type* b, 
     160        TypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, Type* b,
    161161                Kind k, bool s, Type* i = nullptr )
    162162        : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ), init( i ) {}
     
    174174class TypedefDecl final : public NamedTypeDecl {
    175175public:
    176         TypedefDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 
     176        TypedefDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
    177177                Type* b, Linkage::Spec spec = Linkage::Cforall )
    178178        : NamedTypeDecl( loc, name, storage, b, spec ) {}
     
    275275};
    276276
     277
     278//=================================================================================================
     279/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
     280/// remove only if there is a better solution
     281/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
     282/// forward declarations
     283inline void increment( const class Decl * node, Node::ref_type ref ) { node->increment(ref); }
     284inline void decrement( const class Decl * node, Node::ref_type ref ) { node->decrement(ref); }
     285inline void increment( const class DeclWithType * node, Node::ref_type ref ) { node->increment(ref); }
     286inline void decrement( const class DeclWithType * node, Node::ref_type ref ) { node->decrement(ref); }
     287inline void increment( const class ObjectDecl * node, Node::ref_type ref ) { node->increment(ref); }
     288inline void decrement( const class ObjectDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     289inline void increment( const class FunctionDecl * node, Node::ref_type ref ) { node->increment(ref); }
     290inline void decrement( const class FunctionDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     291inline void increment( const class AggregateDecl * node, Node::ref_type ref ) { node->increment(ref); }
     292inline void decrement( const class AggregateDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     293inline void increment( const class StructDecl * node, Node::ref_type ref ) { node->increment(ref); }
     294inline void decrement( const class StructDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     295inline void increment( const class UnionDecl * node, Node::ref_type ref ) { node->increment(ref); }
     296inline void decrement( const class UnionDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     297inline void increment( const class EnumDecl * node, Node::ref_type ref ) { node->increment(ref); }
     298inline void decrement( const class EnumDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     299inline void increment( const class TraitDecl * node, Node::ref_type ref ) { node->increment(ref); }
     300inline void decrement( const class TraitDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     301inline void increment( const class NamedTypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
     302inline void decrement( const class NamedTypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     303inline void increment( const class TypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
     304inline void decrement( const class TypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     305inline void increment( const class FtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
     306inline void decrement( const class FtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     307inline void increment( const class DtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
     308inline void decrement( const class DtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     309inline void increment( const class TypedefDecl * node, Node::ref_type ref ) { node->increment(ref); }
     310inline void decrement( const class TypedefDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     311inline void increment( const class AsmDecl * node, Node::ref_type ref ) { node->increment(ref); }
     312inline void decrement( const class AsmDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     313inline void increment( const class StaticAssertDecl * node, Node::ref_type ref ) { node->increment(ref); }
     314inline void decrement( const class StaticAssertDecl * node, Node::ref_type ref ) { node->decrement(ref); }
     315
    277316}
    278317
  • src/AST/FunctionSpec.hpp

    rb78129a r768b3b4f  
    3131
    3232        /// Bitflag type for storage classes
    33         union Specs {
    34                 unsigned int val;
    35                 struct {
    36                         bool is_inline   : 1;
    37                         bool is_noreturn : 1;
    38                         bool is_fortran  : 1;
     33        struct spec_flags {
     34                union {
     35                        unsigned int val;
     36                        struct {
     37                                bool is_inline   : 1;
     38                                bool is_noreturn : 1;
     39                                bool is_fortran  : 1;
     40                        };
     41
     42                        // MakeBitfieldPrint( NumSpecs )
    3943                };
    4044
    41                 MakeBitfield( Specs )
    42                 MakeBitfieldPrint( NumSpecs )
     45                constexpr spec_flags( unsigned int val ) : val(val) {}
    4346        };
    4447
     48        using Specs = bitfield<spec_flags>;
    4549}
    4650}
  • src/AST/Fwd.hpp

    rb78129a r768b3b4f  
    1616#pragma once
    1717
     18#include "AST/Node.hpp"
     19
    1820namespace ast {
    1921
    20 class Node;
    2122class ParseNode;
    2223
     
    137138class TypeSubstitution;
    138139
     140//=================================================================================================
     141/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
     142/// remove only if there is a better solution
     143/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
     144/// forward declarations
     145inline void decrement( const class Node * node, Node::ref_type ref ) { node->decrement(ref); }
     146inline void increment( const class Node * node, Node::ref_type ref ) { node->increment(ref); }
     147inline void increment( const class ParseNode *, Node::ref_type );
     148inline void decrement( const class ParseNode *, Node::ref_type );
     149inline void increment( const class Decl *, Node::ref_type );
     150inline void decrement( const class Decl *, Node::ref_type );
     151inline void increment( const class DeclWithType *, Node::ref_type );
     152inline void decrement( const class DeclWithType *, Node::ref_type );
     153inline void increment( const class ObjectDecl *, Node::ref_type );
     154inline void decrement( const class ObjectDecl *, Node::ref_type );
     155inline void increment( const class FunctionDecl *, Node::ref_type );
     156inline void decrement( const class FunctionDecl *, Node::ref_type );
     157inline void increment( const class AggregateDecl *, Node::ref_type );
     158inline void decrement( const class AggregateDecl *, Node::ref_type );
     159inline void increment( const class StructDecl *, Node::ref_type );
     160inline void decrement( const class StructDecl *, Node::ref_type );
     161inline void increment( const class UnionDecl *, Node::ref_type );
     162inline void decrement( const class UnionDecl *, Node::ref_type );
     163inline void increment( const class EnumDecl *, Node::ref_type );
     164inline void decrement( const class EnumDecl *, Node::ref_type );
     165inline void increment( const class TraitDecl *, Node::ref_type );
     166inline void decrement( const class TraitDecl *, Node::ref_type );
     167inline void increment( const class NamedTypeDecl *, Node::ref_type );
     168inline void decrement( const class NamedTypeDecl *, Node::ref_type );
     169inline void increment( const class TypeDecl *, Node::ref_type );
     170inline void decrement( const class TypeDecl *, Node::ref_type );
     171inline void increment( const class FtypeDecl *, Node::ref_type );
     172inline void decrement( const class FtypeDecl *, Node::ref_type );
     173inline void increment( const class DtypeDecl *, Node::ref_type );
     174inline void decrement( const class DtypeDecl *, Node::ref_type );
     175inline void increment( const class TypedefDecl *, Node::ref_type );
     176inline void decrement( const class TypedefDecl *, Node::ref_type );
     177inline void increment( const class AsmDecl *, Node::ref_type );
     178inline void decrement( const class AsmDecl *, Node::ref_type );
     179inline void increment( const class StaticAssertDecl *, Node::ref_type );
     180inline void decrement( const class StaticAssertDecl *, Node::ref_type );
     181inline void increment( const class Stmt *, Node::ref_type );
     182inline void decrement( const class Stmt *, Node::ref_type );
     183inline void increment( const class CompoundStmt *, Node::ref_type );
     184inline void decrement( const class CompoundStmt *, Node::ref_type );
     185inline void increment( const class ExprStmt *, Node::ref_type );
     186inline void decrement( const class ExprStmt *, Node::ref_type );
     187inline void increment( const class AsmStmt *, Node::ref_type );
     188inline void decrement( const class AsmStmt *, Node::ref_type );
     189inline void increment( const class DirectiveStmt *, Node::ref_type );
     190inline void decrement( const class DirectiveStmt *, Node::ref_type );
     191inline void increment( const class IfStmt *, Node::ref_type );
     192inline void decrement( const class IfStmt *, Node::ref_type );
     193inline void increment( const class WhileStmt *, Node::ref_type );
     194inline void decrement( const class WhileStmt *, Node::ref_type );
     195inline void increment( const class ForStmt *, Node::ref_type );
     196inline void decrement( const class ForStmt *, Node::ref_type );
     197inline void increment( const class SwitchStmt *, Node::ref_type );
     198inline void decrement( const class SwitchStmt *, Node::ref_type );
     199inline void increment( const class CaseStmt *, Node::ref_type );
     200inline void decrement( const class CaseStmt *, Node::ref_type );
     201inline void increment( const class BranchStmt *, Node::ref_type );
     202inline void decrement( const class BranchStmt *, Node::ref_type );
     203inline void increment( const class ReturnStmt *, Node::ref_type );
     204inline void decrement( const class ReturnStmt *, Node::ref_type );
     205inline void increment( const class ThrowStmt *, Node::ref_type );
     206inline void decrement( const class ThrowStmt *, Node::ref_type );
     207inline void increment( const class TryStmt *, Node::ref_type );
     208inline void decrement( const class TryStmt *, Node::ref_type );
     209inline void increment( const class CatchStmt *, Node::ref_type );
     210inline void decrement( const class CatchStmt *, Node::ref_type );
     211inline void increment( const class FinallyStmt *, Node::ref_type );
     212inline void decrement( const class FinallyStmt *, Node::ref_type );
     213inline void increment( const class WaitForStmt *, Node::ref_type );
     214inline void decrement( const class WaitForStmt *, Node::ref_type );
     215inline void increment( const class WithStmt *, Node::ref_type );
     216inline void decrement( const class WithStmt *, Node::ref_type );
     217inline void increment( const class DeclStmt *, Node::ref_type );
     218inline void decrement( const class DeclStmt *, Node::ref_type );
     219inline void increment( const class NullStmt *, Node::ref_type );
     220inline void decrement( const class NullStmt *, Node::ref_type );
     221inline void increment( const class ImplicitCtorDtorStmt *, Node::ref_type );
     222inline void decrement( const class ImplicitCtorDtorStmt *, Node::ref_type );
     223inline void increment( const class Expr *, Node::ref_type );
     224inline void decrement( const class Expr *, Node::ref_type );
     225inline void increment( const class ApplicationExpr *, Node::ref_type );
     226inline void decrement( const class ApplicationExpr *, Node::ref_type );
     227inline void increment( const class UntypedExpr *, Node::ref_type );
     228inline void decrement( const class UntypedExpr *, Node::ref_type );
     229inline void increment( const class NameExpr *, Node::ref_type );
     230inline void decrement( const class NameExpr *, Node::ref_type );
     231inline void increment( const class AddressExpr *, Node::ref_type );
     232inline void decrement( const class AddressExpr *, Node::ref_type );
     233inline void increment( const class LabelAddressExpr *, Node::ref_type );
     234inline void decrement( const class LabelAddressExpr *, Node::ref_type );
     235inline void increment( const class CastExpr *, Node::ref_type );
     236inline void decrement( const class CastExpr *, Node::ref_type );
     237inline void increment( const class KeywordCastExpr *, Node::ref_type );
     238inline void decrement( const class KeywordCastExpr *, Node::ref_type );
     239inline void increment( const class VirtualCastExpr *, Node::ref_type );
     240inline void decrement( const class VirtualCastExpr *, Node::ref_type );
     241inline void increment( const class MemberExpr *, Node::ref_type );
     242inline void decrement( const class MemberExpr *, Node::ref_type );
     243inline void increment( const class UntypedMemberExpr *, Node::ref_type );
     244inline void decrement( const class UntypedMemberExpr *, Node::ref_type );
     245inline void increment( const class VariableExpr *, Node::ref_type );
     246inline void decrement( const class VariableExpr *, Node::ref_type );
     247inline void increment( const class ConstantExpr *, Node::ref_type );
     248inline void decrement( const class ConstantExpr *, Node::ref_type );
     249inline void increment( const class SizeofExpr *, Node::ref_type );
     250inline void decrement( const class SizeofExpr *, Node::ref_type );
     251inline void increment( const class AlignofExpr *, Node::ref_type );
     252inline void decrement( const class AlignofExpr *, Node::ref_type );
     253inline void increment( const class UntypedOffsetofExpr *, Node::ref_type );
     254inline void decrement( const class UntypedOffsetofExpr *, Node::ref_type );
     255inline void increment( const class OffsetofExpr *, Node::ref_type );
     256inline void decrement( const class OffsetofExpr *, Node::ref_type );
     257inline void increment( const class OffsetPackExpr *, Node::ref_type );
     258inline void decrement( const class OffsetPackExpr *, Node::ref_type );
     259inline void increment( const class AttrExpr *, Node::ref_type );
     260inline void decrement( const class AttrExpr *, Node::ref_type );
     261inline void increment( const class LogicalExpr *, Node::ref_type );
     262inline void decrement( const class LogicalExpr *, Node::ref_type );
     263inline void increment( const class ConditionalExpr *, Node::ref_type );
     264inline void decrement( const class ConditionalExpr *, Node::ref_type );
     265inline void increment( const class CommaExpr *, Node::ref_type );
     266inline void decrement( const class CommaExpr *, Node::ref_type );
     267inline void increment( const class TypeExpr *, Node::ref_type );
     268inline void decrement( const class TypeExpr *, Node::ref_type );
     269inline void increment( const class AsmExpr *, Node::ref_type );
     270inline void decrement( const class AsmExpr *, Node::ref_type );
     271inline void increment( const class ImplicitCopyCtorExpr *, Node::ref_type );
     272inline void decrement( const class ImplicitCopyCtorExpr *, Node::ref_type );
     273inline void increment( const class ConstructorExpr *, Node::ref_type );
     274inline void decrement( const class ConstructorExpr *, Node::ref_type );
     275inline void increment( const class CompoundLiteralExpr *, Node::ref_type );
     276inline void decrement( const class CompoundLiteralExpr *, Node::ref_type );
     277inline void increment( const class UntypedValofExpr *, Node::ref_type );
     278inline void decrement( const class UntypedValofExpr *, Node::ref_type );
     279inline void increment( const class RangeExpr *, Node::ref_type );
     280inline void decrement( const class RangeExpr *, Node::ref_type );
     281inline void increment( const class UntypedTupleExpr *, Node::ref_type );
     282inline void decrement( const class UntypedTupleExpr *, Node::ref_type );
     283inline void increment( const class TupleExpr *, Node::ref_type );
     284inline void decrement( const class TupleExpr *, Node::ref_type );
     285inline void increment( const class TupleIndexExpr *, Node::ref_type );
     286inline void decrement( const class TupleIndexExpr *, Node::ref_type );
     287inline void increment( const class TupleAssignExpr *, Node::ref_type );
     288inline void decrement( const class TupleAssignExpr *, Node::ref_type );
     289inline void increment( const class StmtExpr *, Node::ref_type );
     290inline void decrement( const class StmtExpr *, Node::ref_type );
     291inline void increment( const class UniqueExpr *, Node::ref_type );
     292inline void decrement( const class UniqueExpr *, Node::ref_type );
     293inline void increment( const class UntypedInitExpr *, Node::ref_type );
     294inline void decrement( const class UntypedInitExpr *, Node::ref_type );
     295inline void increment( const class InitExpr *, Node::ref_type );
     296inline void decrement( const class InitExpr *, Node::ref_type );
     297inline void increment( const class DeletedExpr *, Node::ref_type );
     298inline void decrement( const class DeletedExpr *, Node::ref_type );
     299inline void increment( const class DefaultArgExpr *, Node::ref_type );
     300inline void decrement( const class DefaultArgExpr *, Node::ref_type );
     301inline void increment( const class GenericExpr *, Node::ref_type );
     302inline void decrement( const class GenericExpr *, Node::ref_type );
     303inline void increment( const class Type *, Node::ref_type );
     304inline void decrement( const class Type *, Node::ref_type );
     305inline void increment( const class VoidType *, Node::ref_type );
     306inline void decrement( const class VoidType *, Node::ref_type );
     307inline void increment( const class BasicType *, Node::ref_type );
     308inline void decrement( const class BasicType *, Node::ref_type );
     309inline void increment( const class PointerType *, Node::ref_type );
     310inline void decrement( const class PointerType *, Node::ref_type );
     311inline void increment( const class ArrayType *, Node::ref_type );
     312inline void decrement( const class ArrayType *, Node::ref_type );
     313inline void increment( const class ReferenceType *, Node::ref_type );
     314inline void decrement( const class ReferenceType *, Node::ref_type );
     315inline void increment( const class QualifiedType *, Node::ref_type );
     316inline void decrement( const class QualifiedType *, Node::ref_type );
     317inline void increment( const class FunctionType *, Node::ref_type );
     318inline void decrement( const class FunctionType *, Node::ref_type );
     319inline void increment( const class ReferenceToType *, Node::ref_type );
     320inline void decrement( const class ReferenceToType *, Node::ref_type );
     321inline void increment( const class StructInstType *, Node::ref_type );
     322inline void decrement( const class StructInstType *, Node::ref_type );
     323inline void increment( const class UnionInstType *, Node::ref_type );
     324inline void decrement( const class UnionInstType *, Node::ref_type );
     325inline void increment( const class EnumInstType *, Node::ref_type );
     326inline void decrement( const class EnumInstType *, Node::ref_type );
     327inline void increment( const class TraitInstType *, Node::ref_type );
     328inline void decrement( const class TraitInstType *, Node::ref_type );
     329inline void increment( const class TypeInstType *, Node::ref_type );
     330inline void decrement( const class TypeInstType *, Node::ref_type );
     331inline void increment( const class TupleType *, Node::ref_type );
     332inline void decrement( const class TupleType *, Node::ref_type );
     333inline void increment( const class TypeofType *, Node::ref_type );
     334inline void decrement( const class TypeofType *, Node::ref_type );
     335inline void increment( const class AttrType *, Node::ref_type );
     336inline void decrement( const class AttrType *, Node::ref_type );
     337inline void increment( const class VarArgsType *, Node::ref_type );
     338inline void decrement( const class VarArgsType *, Node::ref_type );
     339inline void increment( const class ZeroType *, Node::ref_type );
     340inline void decrement( const class ZeroType *, Node::ref_type );
     341inline void increment( const class OneType *, Node::ref_type );
     342inline void decrement( const class OneType *, Node::ref_type );
     343inline void increment( const class GlobalScopeType *, Node::ref_type );
     344inline void decrement( const class GlobalScopeType *, Node::ref_type );
     345inline void increment( const class Designation *, Node::ref_type );
     346inline void decrement( const class Designation *, Node::ref_type );
     347inline void increment( const class Init *, Node::ref_type );
     348inline void decrement( const class Init *, Node::ref_type );
     349inline void increment( const class SingleInit *, Node::ref_type );
     350inline void decrement( const class SingleInit *, Node::ref_type );
     351inline void increment( const class ListInit *, Node::ref_type );
     352inline void decrement( const class ListInit *, Node::ref_type );
     353inline void increment( const class ConstructorInit *, Node::ref_type );
     354inline void decrement( const class ConstructorInit *, Node::ref_type );
     355inline void increment( const class Constant *, Node::ref_type );
     356inline void decrement( const class Constant *, Node::ref_type );
     357inline void increment( const class Label *, Node::ref_type );
     358inline void decrement( const class Label *, Node::ref_type );
     359inline void increment( const class Attribute *, Node::ref_type );
     360inline void decrement( const class Attribute *, Node::ref_type );
     361inline void increment( const class TypeSubstitution *, Node::ref_type );
     362inline void decrement( const class TypeSubstitution *, Node::ref_type );
     363
    139364typedef unsigned int UniqueId;
    140365
  • src/AST/Init.hpp

    rb78129a r768b3b4f  
    2828class Stmt;
    2929
    30 /// List of designator (NameExpr, VariableExpr, and ConstantExpr) expressions that specify an 
     30/// List of designator (NameExpr, VariableExpr, and ConstantExpr) expressions that specify an
    3131/// object being initialized
    3232class Designation final : public ParseNode {
     
    3434        std::vector<ptr<Expr>> designators;
    3535
    36         Designation( const CodeLocation& loc, std::vector<ptr<Expr>>&& ds = {} ) 
     36        Designation( const CodeLocation& loc, std::vector<ptr<Expr>>&& ds = {} )
    3737        : ParseNode( loc ), designators( std::move(ds) ) {}
    3838
     
    6060        ptr<Expr> value;
    6161
    62         SingleInit( const CodeLocation& loc, Expr* val, bool mc = false ) 
     62        SingleInit( const CodeLocation& loc, Expr* val, bool mc = false )
    6363        : Init( loc, mc ), value( val ) {}
    6464
     
    7777        std::vector<ptr<Designation>> designations;
    7878
    79         ListInit( const CodeLocation& loc, std::vector<ptr<Init>>&& is, 
     79        ListInit( const CodeLocation& loc, std::vector<ptr<Init>>&& is,
    8080                std::vector<ptr<Designation>>&& ds = {}, bool mc = false );
    81        
     81
    8282        using iterator = std::vector<ptr<Init>>::iterator;
    8383        using const_iterator = std::vector<ptr<Init>>::const_iterator;
     
    9393
    9494/// Either a constructor expression or a C-style initializer.
    95 /// Should not be necessary to create manually; instead set `maybeConstructed` true on `SingleInit` 
     95/// Should not be necessary to create manually; instead set `maybeConstructed` true on `SingleInit`
    9696/// or `ListInit` if the object should be constructed.
    9797class ConstructorInit final : public Init {
     
    9999        ptr<Stmt> ctor;
    100100        ptr<Stmt> dtor;
    101         /// C-style initializer made up of SingleInit/ListInit nodes to use as a fallback if an 
     101        /// C-style initializer made up of SingleInit/ListInit nodes to use as a fallback if an
    102102        /// appropriate constructor definition is not found by the resolver.
    103103        ptr<Init> init;
     
    111111};
    112112
     113
     114//=================================================================================================
     115/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
     116/// remove only if there is a better solution
     117/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
     118/// forward declarations
     119inline void increment( const class Init * node, Node::ref_type ref ) { node->increment( ref ); }
     120inline void decrement( const class Init * node, Node::ref_type ref ) { node->decrement( ref ); }
     121inline void increment( const class SingleInit * node, Node::ref_type ref ) { node->increment( ref ); }
     122inline void decrement( const class SingleInit * node, Node::ref_type ref ) { node->decrement( ref ); }
     123inline void increment( const class ListInit * node, Node::ref_type ref ) { node->increment( ref ); }
     124inline void decrement( const class ListInit * node, Node::ref_type ref ) { node->decrement( ref ); }
     125inline void increment( const class ConstructorInit * node, Node::ref_type ref ) { node->increment( ref ); }
     126inline void decrement( const class ConstructorInit * node, Node::ref_type ref ) { node->decrement( ref ); }
    113127}
    114128
  • src/AST/Label.hpp

    rb78129a r768b3b4f  
    2525namespace ast {
    2626
    27         class Attribute;
     27class Attribute;
    2828
    29         /// Named labels for statements
    30         class Label {
    31         public:
    32                 CodeLocation location;
    33                 std::string name;
    34                 std::vector< ptr<Attribute> > attributes;
     29/// Named labels for statements
     30class Label {
     31public:
     32        CodeLocation location;
     33        std::string name;
     34        std::vector< ptr<Attribute> > attributes;
    3535
    36                 Label( CodeLocation loc, const std::string& name = "",
    37                         const std::vector<ptr<Attribute>>& attrs = std::vector<ptr<Attribute>>{} )
    38                 : location( loc ), name( name ), attributes( attrs ) {}
     36        Label( CodeLocation loc, const std::string& name = "",
     37                const std::vector<ptr<Attribute>>& attrs = std::vector<ptr<Attribute>>{} )
     38        : location( loc ), name( name ), attributes( attrs ) {}
    3939
    40                 operator std::string () const { return name; }
    41                 bool empty() { return name.empty(); }
    42         };
     40        operator std::string () const { return name; }
     41        bool empty() { return name.empty(); }
     42};
    4343
    44         inline bool operator== ( const Label& l1, const Label& l2 ) { return l1.name == l2.name; }
    45         inline bool operator!= ( const Label& l1, const Label& l2 ) { return !(l1 == l2); }
    46         inline bool operator<  ( const Label& l1, const Label& l2 ) { return l1.name < l2.name; }
     44inline bool operator== ( const Label& l1, const Label& l2 ) { return l1.name == l2.name; }
     45inline bool operator!= ( const Label& l1, const Label& l2 ) { return !(l1 == l2); }
     46inline bool operator<  ( const Label& l1, const Label& l2 ) { return l1.name < l2.name; }
    4747
    48         inline std::ostream& operator<< ( std::ostream& out, const Label& l ) { return out << l.name; }
     48inline std::ostream& operator<< ( std::ostream& out, const Label& l ) { return out << l.name; }
     49
     50
     51//=================================================================================================
     52/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
     53/// remove only if there is a better solution
     54/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
     55/// forward declarations
     56inline void increment( const class Label * node, Node::ref_type ref ) { node->increment( ref ); }
     57inline void decrement( const class Label * node, Node::ref_type ref ) { node->decrement( ref ); }
    4958
    5059}
  • src/AST/LinkageSpec.hpp

    rb78129a r768b3b4f  
    3535
    3636        /// Bitflag type for storage classes
    37         union Spec {
    38                 unsigned int val;
    39                 struct {
    40                         bool is_mangled      : 1;
    41                         bool is_generatable  : 1;
    42                         bool is_overrideable : 1;
    43                         bool is_builtin      : 1;
    44                         bool is_gcc_builtin  : 1;
     37        struct spec_flags {
     38                union {
     39                        unsigned int val;
     40                        struct {
     41                                bool is_mangled      : 1;
     42                                bool is_generatable  : 1;
     43                                bool is_overrideable : 1;
     44                                bool is_builtin      : 1;
     45                                bool is_gcc_builtin  : 1;
     46                        };
    4547                };
    4648
    47                 MakeBitfield( Spec )
     49                constexpr spec_flags( unsigned int val ) : val(val) {}
    4850        };
     51
     52        using Spec = bitfield<spec_flags>;
    4953
    5054        /// If `cmd` = "C" returns `spec` with `is_mangled = false`.
  • src/AST/ParseNode.hpp

    rb78129a r768b3b4f  
    2222namespace ast {
    2323
    24         /// AST node with an included source location
    25         class ParseNode : public Node {
    26         public:
    27                 CodeLocation location;
     24/// AST node with an included source location
     25class ParseNode : public Node {
     26public:
     27        CodeLocation location;
    2828
    29                 // Default constructor is deliberately omitted, all ParseNodes must have a location.
    30                 // Escape hatch if needed is to explicitly pass a default-constructed location, but
    31                 // this should be used sparingly.
     29        // Default constructor is deliberately omitted, all ParseNodes must have a location.
     30        // Escape hatch if needed is to explicitly pass a default-constructed location, but
     31        // this should be used sparingly.
    3232
    33                 ParseNode( const CodeLocation& loc ) : Node(), location(loc) {}
     33        ParseNode( const CodeLocation& loc ) : Node(), location(loc) {}
    3434
    35                 ParseNode( const ParseNode& o ) = default;
    36         };
     35        ParseNode( const ParseNode& o ) = default;
     36};
    3737
     38
     39//=================================================================================================
     40/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
     41/// remove only if there is a better solution
     42/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
     43/// forward declarations
     44inline void increment( const class ParseNode * node, Node::ref_type ref ) { node->increment( ref ); }
     45inline void decrement( const class ParseNode * node, Node::ref_type ref ) { node->decrement( ref ); }
    3846}
    3947
  • src/AST/Pass.hpp

    rb78129a r768b3b4f  
     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.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
    2 // IWYU pragma: private, include "Common/PassVisitor.h"
     17// IWYU pragma: private, include "AST/Pass.hpp"
    318
    419#include <functional>
     
    621#include <stack>
    722
    8 #include "Fwd.hpp"
    9 #include "Node.hpp"
     23#include "AST/Fwd.hpp"
     24#include "AST/Node.hpp"
     25#include "AST/Decl.hpp"
     26#include "AST/Visitor.hpp"
     27
     28#include "SymTab/Indexer.h"
    1029
    1130// Private prelude header, needed for some of the magic tricks this class pulls off
    12 #include "Pass.proto.hpp"
     31#include "AST/Pass.proto.hpp"
    1332
    1433namespace ast {
     
    2039//
    2140// Several additional features are available through inheritance
    22 // | WithTypeSubstitution - provides polymorphic TypeSubstitution * env for the current expression
     41// | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
     42//                          current expression
    2343// | WithStmtsToAdd       - provides the ability to insert statements before or after the current
    2444//                          statement by adding new statements into stmtsToAddBefore or
    2545//                          stmtsToAddAfter respectively.
     46// | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
     47//                          declarations by adding new DeclStmt into declsToAddBefore or
     48//                          declsToAddAfter respectively.
    2649// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
    2750//                          to false in pre{visit,visit} to skip visiting children
     
    3053//                          automatically be restored to its previous value after the corresponding
    3154//                          postvisit/postmutate teminates.
     55// | WithVisitorRef       - provides an pointer to the templated visitor wrapper
     56// | WithIndexer          - provides indexer functionality (i.e. up-to-date symbol table)
    3257//-------------------------------------------------------------------------------------------------
    3358template< typename pass_t >
    3459class Pass final : public ast::Visitor {
    3560public:
     61        /// Forward any arguments to the pass constructor
     62        /// Propagate 'this' if necessary
    3663        template< typename... Args >
    3764        Pass( Args &&... args)
    38                 : m_pass( std::forward<Args>( args )... )
     65                : pass( std::forward<Args>( args )... )
    3966        {
    4067                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    4168                typedef Pass<pass_t> this_t;
    42                 this_t * const * visitor = __pass::visitor(m_pass, 0);
     69                this_t * const * visitor = __pass::visitor(pass, 0);
    4370                if(visitor) {
    4471                        *const_cast<this_t **>( visitor ) = this;
     
    4875        virtual ~Pass() = default;
    4976
    50         pass_t m_pass;
    51 
     77        /// Storage for the actual pass
     78        pass_t pass;
     79
     80        /// Visit function declarations
    5281        virtual DeclWithType *     visit( const ObjectDecl           * ) override final;
    5382        virtual DeclWithType *     visit( const FunctionDecl         * ) override final;
     
    145174        virtual TypeSubstitution * visit( const TypeSubstitution     * ) override final;
    146175
     176        friend void acceptAll( std::list< ptr<Decl> > & decls, Pass<pass_t>& visitor );
    147177private:
    148178
    149         bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(m_pass, 0); return ptr ? *ptr : true; }
     179        bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
    150180
    151181private:
     182        /// Logic to call the accept and mutate the parent if needed, delegates call to accept
    152183        template<typename parent_t, typename child_t>
    153184        void maybe_accept(parent_t * & , typename parent_t::child_t *);
    154185
    155         ast::Statement  * call_accept( const ast::Statement * );
    156         ast::Expression * call_accept( const ast::Expression * );
     186        Stmt * call_accept( const Stmt * );
     187        Expr * call_accept( const Expr * );
    157188
    158189        template< template <class> class container_t >
    159         container_t< ast::ptr<ast::Statement> > call_accept( const container_t< ast::ptr<ast::Statement> > & );
     190        container_t< ptr<Stmt> > call_accept( const container_t< ptr<Stmt> > & );
    160191
    161192        template< template <class> class container_t, typename node_t >
    162         container_t< ast::ptr<node_t> > call_accept( const container_t< ast::ptr<node_t> > & container );
     193        container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    163194
    164195private:
    165         struct indexer_guard {
     196        /// Internal RAII guard for indexer features
     197        struct guard_indexer {
     198                guard_indexer( Pass<pass_t> & pass ): pass( pass ) { __pass::indexer::enter(pass, 0); }
     199                ~guard_indexer()                                   { __pass::indexer::leave(pass, 0); }
    166200                Pass<pass_t> & pass;
    167 
    168                 indexer_guard( Pass<pass_t> & pass ) : pass( pass ) { __pass::indexer::enter(pass, 0); }
    169                 ~indexer_guard()                                    { __pass::indexer::leave(pass, 0); }
    170201        };
    171202
    172         indexer_guard make_indexer_guard() { return { *this }; }
    173 
    174 private:
    175         struct scope_guard {
     203        /// Internal RAII guard for scope features
     204        struct guard_scope {
     205                guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
     206                ~guard_scope()                                   { __pass::scope::leave(pass, 0); }
    176207                Pass<pass_t> & pass;
    177 
    178                 scope_guard( Pass<pass_t> & pass ) : pass( pass ) { __pass::scope::enter(pass, 0); }
    179                 ~scope_guard()                                    { __pass::scope::leave(pass, 0); }
    180208        };
    181 
    182         scope_guard make_scope_guard() { return { *this }; }
    183 };
    184 
    185 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    186 // Guard value : RAII type to restore a value when the Pass finishes visiting this node
    187 template<typename pass_t, typename T>
    188 void GuardValue( pass_t * pass, T& val ) {
    189         pass->at_cleanup( [ val ]( void * newVal ) {
    190                 * static_cast< T * >( newVal ) = val;
    191         }, static_cast< void * >( & val ) );
    192 }
    193 
    194 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     209};
     210
     211template<typename pass_t>
     212void acceptAll( std::list< ptr<Decl> >, Pass<pass_t>& visitor );
     213
     214//-------------------------------------------------------------------------------------------------
    195215// PASS ACCESSORIES
    196 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    197 
    198 // Keep track of the type substitution
    199 struct WithConstTypeSubstitution {
    200         const ast::TypeSubstitution * env = nullptr;
    201 };
     216//-------------------------------------------------------------------------------------------------
    202217
    203218template<typename T>
    204219using std_list = std::list<T>;
    205220
    206 // Used if visitor requires added statements before or after the current node.
    207 // The Pass template handles what *before* and *after* means automatically
     221/// Keep track of the polymorphic const TypeSubstitution * env for the current expression
     222struct WithConstTypeSubstitution {
     223        const TypeSubstitution * env = nullptr;
     224};
     225
     226/// Used if visitor requires added statements before or after the current node.
     227/// The Pass template handles what *before* and *after* means automatically
    208228template< template<class> class container_t = std_list >
    209229struct WithStmtsToAdd {
    210         container_t< ast::ptr< ast::Statement > > stmtsToAddBefore;
    211         container_t< ast::ptr< ast::Statement > > stmtsToAddAfter;
    212 };
    213 
    214 // Used if visitor requires added declarations before or after the current node.
    215 // The Pass template handles what *before* and *after* means automatically
     230        container_t< ptr<Stmt> > stmtsToAddBefore;
     231        container_t< ptr<Stmt> > stmtsToAddAfter;
     232};
     233
     234/// Used if visitor requires added declarations before or after the current node.
     235/// The Pass template handles what *before* and *after* means automatically
    216236template< template<class> class container_t = std_list >
    217237struct WithDeclsToAdd {
    218         ~WithDeclsToAdd() {
    219                 assert( declsToAddBefore.empty() );
    220         }
    221 
    222         container_t< ast::ptr< ast::Declaration > > declsToAddBefore;
    223         container_t< ast::ptr< ast::Declaration > > declsToAddAfter;
    224 };
    225 
    226 // Use if visitation should stop at certain levels
    227 // set visit_children false of all child nodes should be ignored
     238        container_t< ptr<Decl> > declsToAddBefore;
     239        container_t< ptr<Decl> > declsToAddAfter;
     240};
     241
     242/// Use if visitation should stop at certain levels
     243/// set visit_children false of all child nodes should be ignored
    228244struct WithShortCircuiting {
    229245        __pass::bool_ref visit_children;
    230246};
    231247
    232 // class WithGuards {
    233 // protected:
    234 //      WithGuards() = default;
    235 //      ~WithGuards() = default;
    236 
    237 // public:
    238 //      at_cleanup_t at_cleanup;
    239 
    240 //      template< typename T >
    241 //      void GuardValue( T& val ) {
    242 //              at_cleanup( [ val ]( void * newVal ) {
    243 //                      * static_cast< T * >( newVal ) = val;
    244 //              }, static_cast< void * >( & val ) );
    245 //      }
    246 
    247 //      template< typename T >
    248 //      void GuardScope( T& val ) {
    249 //              val.beginScope();
    250 //              at_cleanup( []( void * val ) {
    251 //                      static_cast< T * >( val )->endScope();
    252 //              }, static_cast< void * >( & val ) );
    253 //      }
    254 
    255 //      template< typename Func >
    256 //      void GuardAction( Func func ) {
    257 //              at_cleanup( [func](__attribute__((unused)) void *) { func(); }, nullptr );
    258 //      }
    259 // };
    260 
    261 // template<typename pass_type>
    262 // class WithVisitorRef {
    263 // protected:
    264 //      WithVisitorRef() {}
    265 //      ~WithVisitorRef() {}
    266 
    267 // public:
    268 //      PassVisitor<pass_type> * const visitor = nullptr;
    269 // };
    270 
     248/// Used to restore values/functions/etc. when the Pass finishes visiting this node
     249class WithGuards {
     250        __pass::at_cleanup_t at_cleanup;
     251
     252public:
     253        /// When this node is finished being visited, restore the value of a variable
     254        template< typename T >
     255        void GuardValue( T& val ) {
     256                at_cleanup( [ val ]( void * newVal ) {
     257                        * static_cast< T * >( newVal ) = val;
     258                }, static_cast< void * >( & val ) );
     259        }
     260
     261        /// On the object, all beginScope now and endScope when the current node is finished being visited
     262        template< typename T >
     263        void GuardScope( T& val ) {
     264                val.beginScope();
     265                at_cleanup( []( void * val ) {
     266                        static_cast< T * >( val )->endScope();
     267                }, static_cast< void * >( & val ) );
     268        }
     269
     270        /// When this node is finished being visited, call a function
     271        template< typename Func >
     272        void GuardAction( Func func ) {
     273                at_cleanup( [func](void *) { func(); }, nullptr );
     274        }
     275};
     276
     277/// Used to get a pointer to the pass with its wrapped type
     278template<typename pass_t>
     279struct WithVisitorRef {
     280        Pass<pass_t> * const visitor = nullptr;
     281};
     282
     283/// Use when the templated visitor should update the indexer
    271284struct WithIndexer {
    272285        SymTab::Indexer indexer;
  • src/AST/Pass.impl.hpp

    rb78129a r768b3b4f  
     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
    2 // IWYU pragma: private, include "Pass.hpp"
     17// IWYU pragma: private, include "AST/Pass.hpp"
    318
    419#define VISIT_START( node ) \
     20        using namespace ast; \
    521        /* back-up the visit children */ \
    6         __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(m_pass, 0) ); \
     22        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
    723        /* setup the scope for passes that want to run code at exit */ \
    8         __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (m_pass, 0) ); \
     24        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
    925        /* call the implementation of the previsit of this pass */ \
    10         __pass::previsit( m_pass, node, 0 );
     26        __pass::previsit( pass, node, 0 );
    1127
    1228#define VISIT( code ) \
     
    98114
    99115        template< typename pass_t >
    100         ast::Expression * Pass< pass_t >::call_accept( const ast::Expression * expr ) {
     116        ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
    101117                __pedantic_pass_assert( __visit_children() );
    102118                __pedantic_pass_assert( expr );
    103119
    104                 const ast::TypeSubstitution ** env_ptr = __pass::env( m_pass, 0);
     120                const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
    105121                if ( env_ptr && expr->env ) {
    106122                        *env_ptr = expr->env;
     
    111127
    112128        template< typename pass_t >
    113         ast::Statement * Pass< pass_t >::call_accept( const ast::Statement * stmt ) {
     129        Stmt * Pass< pass_t >::call_accept( const Stmt * stmt ) {
    114130                __pedantic_pass_assert( __visit_children() );
    115131                __pedantic_pass_assert( stmt );
    116 
    117                 // add a few useful symbols to the scope
    118                 using __pass::empty;
    119                 using decls_t = typename std::remove_pointer< decltype(__decls_before()) >::type;
    120                 using stmts_t = typename std::remove_pointer< decltype(__stmts_before()) >::type;
    121 
    122                 // get the stmts/decls that will need to be spliced in
    123                 auto stmts_before = __pass::stmtsToAddBefore( m_pass, 0);
    124                 auto stmts_after  = __pass::stmtsToAddAfter ( m_pass, 0);
    125                 auto decls_before = __pass::declsToAddBefore( m_pass, 0);
    126                 auto decls_after  = __pass::declsToAddAfter ( m_pass, 0);
    127 
    128                 // These may be modified by subnode but most be restored once we exit this statemnet.
    129                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( m_pass, 0);  );
    130                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
    131                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
    132                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
    133                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
    134 
    135                 // Now is the time to actually visit the node
    136                 ast::Statement * nstmt = stmt->accept( *this );
    137 
    138                 // If the pass doesn't want to add anything then we are done
    139                 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
    140                         return nstmt;
    141                 }
    142 
    143                 // Make sure that it is either adding statements or declartions but not both
    144                 // this is because otherwise the order would be awkward to predict
    145                 assert(( empty( stmts_before ) && empty( stmts_after ))
    146                     || ( empty( decls_before ) && empty( decls_after )) );
    147 
    148                 // Create a new Compound Statement to hold the new decls/stmts
    149                 ast::CompoundStmt * compound = new ast::CompoundStmt( parent->*child.location );
    150 
    151                 // Take all the declarations that go before
    152                 __pass::take_all( std::back_inserter( compound->kids ), decls_before );
    153                 __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
    154 
    155                 // Insert the original declaration
    156                 compound->kids.push_back( nstmt );
    157 
    158                 // Insert all the declarations that go before
    159                 __pass::take_all( std::back_inserter( compound->kids ), decls_after );
    160                 __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
    161 
    162                 return compound;
    163         }
    164 
    165         template< typename pass_t >
    166         template< template <class> class container_t >
    167         container_t< ast::ptr<ast::Statement> > Pass< pass_t >::call_accept( const container_t< ast::ptr<ast::Statement> > & statements ) {
    168                 __pedantic_pass_assert( __visit_children() );
    169                 if( statements.empty() ) return {};
    170 
    171                 // We are going to aggregate errors for all these statements
    172                 SemanticErrorException errors;
    173132
    174133                // add a few useful symbols to the scope
     
    182141
    183142                // These may be modified by subnode but most be restored once we exit this statemnet.
     143                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0);  );
    184144                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
    185145                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
     
    187147                ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
    188148
     149                // Now is the time to actually visit the node
     150                ast::Statement * nstmt = stmt->accept( *this );
     151
     152                // If the pass doesn't want to add anything then we are done
     153                if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
     154                        return nstmt;
     155                }
     156
     157                // Make sure that it is either adding statements or declartions but not both
     158                // this is because otherwise the order would be awkward to predict
     159                assert(( empty( stmts_before ) && empty( stmts_after ))
     160                    || ( empty( decls_before ) && empty( decls_after )) );
     161
     162                // Create a new Compound Statement to hold the new decls/stmts
     163                ast::CompoundStmt * compound = new ast::CompoundStmt( parent->*child.location );
     164
     165                // Take all the declarations that go before
     166                __pass::take_all( std::back_inserter( compound->kids ), decls_before );
     167                __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
     168
     169                // Insert the original declaration
     170                compound->kids.push_back( nstmt );
     171
     172                // Insert all the declarations that go before
     173                __pass::take_all( std::back_inserter( compound->kids ), decls_after );
     174                __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
     175
     176                return compound;
     177        }
     178
     179        template< typename pass_t >
     180        template< template <class> class container_t >
     181        container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     182                __pedantic_pass_assert( __visit_children() );
     183                if( statements.empty() ) return {};
     184
     185                // We are going to aggregate errors for all these statements
     186                SemanticErrorException errors;
     187
     188                // add a few useful symbols to the scope
     189                using __pass::empty;
     190
     191                // get the stmts/decls that will need to be spliced in
     192                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
     193                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     194                auto decls_before = __pass::declsToAddBefore( pass, 0);
     195                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
     196
     197                // These may be modified by subnode but most be restored once we exit this statemnet.
     198                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
     199                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
     200                ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
     201                ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
     202
    189203                // update pass statitistics
    190204                pass_visitor_stats.depth++;
     
    193207
    194208                bool mutated = false;
    195                 container_t<ast::ptr< ast::Statement >> new_kids;
    196                 for( const ast::Statement * stmt : statements ) {
     209                container_t< ptr<Stmt> > new_kids;
     210                for( const Stmt * stmt : statements ) {
    197211                        try {
    198212                                __pedantic_pass_assert( stmt );
     
    269283//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    270284
     285template< typename pass_t >
     286inline void ast::acceptAll( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
     287        // We are going to aggregate errors for all these statements
     288        SemanticErrorException errors;
     289
     290        // add a few useful symbols to the scope
     291        using __pass::empty;
     292
     293        // get the stmts/decls that will need to be spliced in
     294        auto decls_before = __pass::declsToAddBefore( pass, 0);
     295        auto decls_after  = __pass::declsToAddAfter ( pass, 0);
     296
     297        // update pass statitistics
     298        pass_visitor_stats.depth++;
     299        pass_visitor_stats.max->push(pass_visitor_stats.depth);
     300        pass_visitor_stats.avg->push(pass_visitor_stats.depth);
     301
     302        for ( std::list< ast::ptr<ast::Decl> >::iterator i = decls.begin(); ; ++i ) {
     303                // splice in new declarations after previous decl
     304                if ( !empty( decls_after ) ) { decls.splice( i, *decls_after ); }
     305
     306                if ( i == decls.end() ) break;
     307
     308                try {
     309                        // run visitor on declaration
     310                        ast::ptr<ast::Decl> & node = *i;
     311                        assert( node );
     312                        node = node->accept( visitor );
     313                }
     314                catch( SemanticErrorException &e ) {
     315                        errors.append( e );
     316                }
     317
     318                // splice in new declarations before current decl
     319                if ( !empty( decls_before ) ) { decls.splice( i, *decls_before ); }
     320        }
     321        pass_visitor_stats.depth--;
     322        if ( !errors.isEmpty() ) { throw errors; }
     323}
     324
    271325// A NOTE ON THE ORDER OF TRAVERSAL
    272326//
     
    289343// ObjectDecl
    290344template< typename pass_t >
    291 ast::DeclarationWithType * Pass< pass_t >::mutate( ast::ObjectDecl * node ) {
     345ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
    292346        VISIT_START( node );
    293347
    294348        VISIT(
    295349                {
    296                         auto guard = make_indexer_guard();
    297                         maybe_accept( node, ast::ObjectDecl::type );
    298                 }
    299                 maybe_accept( node, ast::ObjectDecl::init          );
    300                 maybe_accept( node, ast::ObjectDecl::bitfieldWidth );
    301                 maybe_accept( node, ast::ObjectDecl::attributes    );
     350                        indexer_guard guard { *this };
     351                        maybe_accept( node, ObjectDecl::type );
     352                }
     353                maybe_accept( node, ObjectDecl::init          );
     354                maybe_accept( node, ObjectDecl::bitfieldWidth );
     355                maybe_accept( node, ObjectDecl::attributes    );
    302356        )
    303357
    304         __pass::indexer::AddId( m_pass, 0, node );
    305 
    306         VISIT_END( DeclarationWithType, node );
     358        __pass::indexer::AddId( pass, 0, node );
     359
     360        VISIT_END( DeclWithType, node );
    307361}
    308362
     
    310364// Attribute
    311365template< typename pass_type >
    312 ast::Attribute * ast::Pass< pass_type >::visit( ast::ptr<ast::Attribute> & node  )  {
     366ast::Attribute * ast::Pass< pass_type >::visit( const ast::Attribute * node  )  {
    313367        VISIT_START(node);
    314368
     
    323377// TypeSubstitution
    324378template< typename pass_type >
    325 TypeSubstitution * PassVisitor< pass_type >::mutate( TypeSubstitution * node ) {
     379TypeSubstitution * PassVisitor< pass_type >::mutate( const TypeSubstitution * node ) {
    326380        MUTATE_START( node );
    327381
  • src/AST/Pass.proto.hpp

    rb78129a r768b3b4f  
     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};
  • src/AST/Stmt.hpp

    rb78129a r768b3b4f  
    8989
    9090
     91//=================================================================================================
     92/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
     93/// remove only if there is a better solution
     94/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
     95/// forward declarations
     96inline void increment( const class Stmt * node, Node::ref_type ref ) { node->increment( ref ); }
     97inline void decrement( const class Stmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     98inline void increment( const class CompoundStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     99inline void decrement( const class CompoundStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     100inline void increment( const class ExprStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     101inline void decrement( const class ExprStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     102inline void increment( const class AsmStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     103inline void decrement( const class AsmStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     104inline void increment( const class DirectiveStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     105inline void decrement( const class DirectiveStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     106inline void increment( const class IfStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     107inline void decrement( const class IfStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     108inline void increment( const class WhileStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     109inline void decrement( const class WhileStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     110inline void increment( const class ForStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     111inline void decrement( const class ForStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     112inline void increment( const class SwitchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     113inline void decrement( const class SwitchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     114inline void increment( const class CaseStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     115inline void decrement( const class CaseStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     116inline void increment( const class BranchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     117inline void decrement( const class BranchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     118inline void increment( const class ReturnStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     119inline void decrement( const class ReturnStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     120inline void increment( const class ThrowStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     121inline void decrement( const class ThrowStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     122inline void increment( const class TryStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     123inline void decrement( const class TryStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     124inline void increment( const class CatchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     125inline void decrement( const class CatchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     126inline void increment( const class FinallyStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     127inline void decrement( const class FinallyStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     128inline void increment( const class WaitForStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     129inline void decrement( const class WaitForStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     130inline void increment( const class WithStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     131inline void decrement( const class WithStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     132inline void increment( const class DeclStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     133inline void decrement( const class DeclStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     134inline void increment( const class NullStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     135inline void decrement( const class NullStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     136inline void increment( const class ImplicitCtorDtorStmt * node, Node::ref_type ref ) { node->increment( ref ); }
     137inline void decrement( const class ImplicitCtorDtorStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
     138
    91139}
    92140
  • src/AST/StorageClasses.hpp

    rb78129a r768b3b4f  
    3333
    3434        /// Bitflag type for storage classes
    35         union Classes {
    36                 unsigned int val;
    37                 struct {
    38                         bool is_extern      : 1;
    39                         bool is_static      : 1;
    40                         bool is_auto        : 1;
    41                         bool is_register    : 1;
    42                         bool is_threadlocal : 1;
     35        struct class_flags {
     36                union {
     37                        unsigned int val;
     38                        struct {
     39                                bool is_extern      : 1;
     40                                bool is_static      : 1;
     41                                bool is_auto        : 1;
     42                                bool is_register    : 1;
     43                                bool is_threadlocal : 1;
     44                        };
     45
     46                        // MakeBitfieldPrint( NumClasses )
    4347                };
    4448
    45                 MakeBitfield( Classes )
    46                 MakeBitfieldPrint( NumClasses )
     49                constexpr class_flags( unsigned int val ) : val(val) {}
    4750        };
    4851
     52        using Classes = bitfield<class_flags>;
    4953}
    5054}
  • src/AST/Type.hpp

    rb78129a r768b3b4f  
    2424};
    2525
     26
     27
     28//=================================================================================================
     29/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
     30/// remove only if there is a better solution
     31/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
     32/// forward declarations
     33inline void increment( const class Type * node, Node::ref_type ref ) { node->increment( ref ); }
     34inline void decrement( const class Type * node, Node::ref_type ref ) { node->decrement( ref ); }
     35inline void increment( const class VoidType * node, Node::ref_type ref ) { node->increment( ref ); }
     36inline void decrement( const class VoidType * node, Node::ref_type ref ) { node->decrement( ref ); }
     37inline void increment( const class BasicType * node, Node::ref_type ref ) { node->increment( ref ); }
     38inline void decrement( const class BasicType * node, Node::ref_type ref ) { node->decrement( ref ); }
     39inline void increment( const class PointerType * node, Node::ref_type ref ) { node->increment( ref ); }
     40inline void decrement( const class PointerType * node, Node::ref_type ref ) { node->decrement( ref ); }
     41inline void increment( const class ArrayType * node, Node::ref_type ref ) { node->increment( ref ); }
     42inline void decrement( const class ArrayType * node, Node::ref_type ref ) { node->decrement( ref ); }
     43inline void increment( const class ReferenceType * node, Node::ref_type ref ) { node->increment( ref ); }
     44inline void decrement( const class ReferenceType * node, Node::ref_type ref ) { node->decrement( ref ); }
     45inline void increment( const class QualifiedType * node, Node::ref_type ref ) { node->increment( ref ); }
     46inline void decrement( const class QualifiedType * node, Node::ref_type ref ) { node->decrement( ref ); }
     47inline void increment( const class FunctionType * node, Node::ref_type ref ) { node->increment( ref ); }
     48inline void decrement( const class FunctionType * node, Node::ref_type ref ) { node->decrement( ref ); }
     49inline void increment( const class ReferenceToType * node, Node::ref_type ref ) { node->increment( ref ); }
     50inline void decrement( const class ReferenceToType * node, Node::ref_type ref ) { node->decrement( ref ); }
     51inline void increment( const class StructInstType * node, Node::ref_type ref ) { node->increment( ref ); }
     52inline void decrement( const class StructInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
     53inline void increment( const class UnionInstType * node, Node::ref_type ref ) { node->increment( ref ); }
     54inline void decrement( const class UnionInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
     55inline void increment( const class EnumInstType * node, Node::ref_type ref ) { node->increment( ref ); }
     56inline void decrement( const class EnumInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
     57inline void increment( const class TraitInstType * node, Node::ref_type ref ) { node->increment( ref ); }
     58inline void decrement( const class TraitInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
     59inline void increment( const class TypeInstType * node, Node::ref_type ref ) { node->increment( ref ); }
     60inline void decrement( const class TypeInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
     61inline void increment( const class TupleType * node, Node::ref_type ref ) { node->increment( ref ); }
     62inline void decrement( const class TupleType * node, Node::ref_type ref ) { node->decrement( ref ); }
     63inline void increment( const class TypeofType * node, Node::ref_type ref ) { node->increment( ref ); }
     64inline void decrement( const class TypeofType * node, Node::ref_type ref ) { node->decrement( ref ); }
     65inline void increment( const class AttrType * node, Node::ref_type ref ) { node->increment( ref ); }
     66inline void decrement( const class AttrType * node, Node::ref_type ref ) { node->decrement( ref ); }
     67inline void increment( const class VarArgsType * node, Node::ref_type ref ) { node->increment( ref ); }
     68inline void decrement( const class VarArgsType * node, Node::ref_type ref ) { node->decrement( ref ); }
     69inline void increment( const class ZeroType * node, Node::ref_type ref ) { node->increment( ref ); }
     70inline void decrement( const class ZeroType * node, Node::ref_type ref ) { node->decrement( ref ); }
     71inline void increment( const class OneType * node, Node::ref_type ref ) { node->increment( ref ); }
     72inline void decrement( const class OneType * node, Node::ref_type ref ) { node->decrement( ref ); }
     73inline void increment( const class GlobalScopeType * node, Node::ref_type ref ) { node->increment( ref ); }
     74inline void decrement( const class GlobalScopeType * node, Node::ref_type ref ) { node->decrement( ref ); }
     75
    2676}
    2777
  • src/AST/porting.md

    rb78129a r768b3b4f  
    9696
    9797`Expr`
    98 * Merged `inferParams`/`resnSlots` into union, as suggested by comment
     98* Merged `inferParams`/`resnSlots` into union, as suggested by comment in old version
     99  * does imply get_/set_ API, and some care about moving backward
    99100
    100101`Label`
  • src/Common/PassVisitor.impl.h

    rb78129a r768b3b4f  
    168168template< typename Container, typename pass_type >
    169169inline void maybeMutate_impl( Container & container, PassVisitor< pass_type > & mutator ) {
     170
    170171        if ( ! mutator.get_visit_children() ) return;
    171172        SemanticErrorException errors;
     
    217218                try {
    218219                        func( *i );
     220                        assert( *i );
    219221                        assert(( empty( beforeStmts ) && empty( afterStmts ))
    220222                            || ( empty( beforeDecls ) && empty( afterDecls )) );
  • src/Common/PassVisitor.proto.h

    rb78129a r768b3b4f  
    222222INDEXER_FUNC2( addWith   , std::list< Expression * > &, BaseSyntaxNode * );
    223223
     224#undef INDEXER_FUNC1
     225#undef INDEXER_FUNC2
    224226
    225227template<typename pass_type>
  • src/SynTree/Declaration.h

    rb78129a r768b3b4f  
    7171        static Declaration *declFromId( UniqueId id );
    7272
    73   private:
     73        UniqueId uniqueId;
    7474        Type::StorageClasses storageClasses;
    75         UniqueId uniqueId;
     75  private:
    7676};
    7777
     
    213213                TypeDecl::Kind kind;
    214214                bool isComplete;
    215                
     215
    216216                Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {}
    217217                Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
    218218                Data( Kind kind, bool isComplete ) : kind( kind ), isComplete( isComplete ) {}
    219                 Data( const Data& d1, const Data& d2 ) 
     219                Data( const Data& d1, const Data& d2 )
    220220                : kind( d1.kind ), isComplete ( d1.isComplete || d2.isComplete ) {}
    221221
Note: See TracChangeset for help on using the changeset viewer.