Changeset 2a301ff for src


Ignore:
Timestamp:
Aug 31, 2023, 11:31:15 PM (2 years ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
950c58e
Parents:
92355883 (diff), 686912c (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:

Resolve conflict

Location:
src
Files:
41 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Create.cpp

    r92355883 r2a301ff  
    4242                return nullptr;
    4343        }
    44         return new ast::FunctionDecl( decl->location,
    45                 decl->name,
    46                 vectorCopy( decl->type_params ),
    47                 vectorCopy( decl->assertions ),
    48                 vectorCopy( decl->params ),
    49                 vectorCopy( decl->returns ),
    50                 nullptr,
    51                 decl->storage,
    52                 decl->linkage,
    53                 vectorCopy( decl->attributes ),
    54                 decl->funcSpec,
    55                 decl->type->isVarArgs
    56         );
     44        // The cast and changing the original should be safe as long as the
     45        // change is reverted before anything else sees it. It's also faster.
     46        FunctionDecl * mutDecl = const_cast<FunctionDecl *>( decl );
     47        CompoundStmt const * stmts = mutDecl->stmts.release();
     48        FunctionDecl * copy = deepCopy( mutDecl );
     49        mutDecl->stmts = stmts;
     50        return copy;
    5751}
    5852
  • src/AST/Decl.cpp

    r92355883 r2a301ff  
    115115        static_assert( sizeof(kindNames) / sizeof(kindNames[0]) == TypeDecl::NUMBER_OF_KINDS, "typeString: kindNames is out of sync." );
    116116        assertf( kind < TypeDecl::NUMBER_OF_KINDS, "TypeDecl kind is out of bounds." );
    117         return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0'
     117        // sizeof("sized") includes '\0' and gives the offset to remove "sized ".
     118        return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ];
    118119}
    119120
  • src/AST/Decl.hpp

    r92355883 r2a301ff  
    6969public:
    7070        /// Represents the type with all types and typedefs expanded.
    71         /// This field is generated by SymTab::Validate::Pass2
    7271        std::string mangleName;
    7372        /// Stores the scope level at which the variable was declared.
  • src/AST/LinkageSpec.cpp

    r92355883 r2a301ff  
    2727namespace Linkage {
    2828
    29         Spec update( CodeLocation loc, Spec spec, const std::string * cmd ) {
    30                 assert( cmd );
    31                 std::unique_ptr<const std::string> guard( cmd ); // allocated by lexer
    32                 if ( *cmd == "\"Cforall\"" ) {
    33                         spec.is_mangled = true;
    34                         return spec;
    35                 } else if ( *cmd == "\"C\"" ) {
    36                         spec.is_mangled = false;
    37                         return spec;
    38                 } else {
    39                         SemanticError( loc, "Invalid linkage specifier " + *cmd );
    40                 }
     29Spec update( CodeLocation loc, Spec spec, const std::string * cmd ) {
     30        assert( cmd );
     31        std::unique_ptr<const std::string> guard( cmd ); // allocated by lexer
     32        if ( *cmd == "\"Cforall\"" ) {
     33                spec.is_mangled = true;
     34                return spec;
     35        } else if ( *cmd == "\"C\"" ) {
     36                spec.is_mangled = false;
     37                return spec;
     38        } else {
     39                SemanticError( loc, "Invalid linkage specifier " + *cmd );
    4140        }
     41}
    4242
    43 
    44         std::string name( Spec spec ) {
    45                 switch ( spec.val ) {
    46                 case Intrinsic.val:  return "intrinsic";
    47                 case C.val:          return "C";
    48                 case Cforall.val:    return "Cforall";
    49                 case AutoGen.val:    return "autogenerated cfa";
    50                 case Compiler.val:   return "compiler built-in";
    51                 case BuiltinCFA.val: return "cfa built-in";
    52                 case BuiltinC.val:   return "c built-in";
    53                 default:         return "<unnamed linkage spec>";
    54                 }
     43std::string name( Spec spec ) {
     44        switch ( spec.val ) {
     45        case Intrinsic.val:  return "intrinsic";
     46        case C.val:          return "C";
     47        case Cforall.val:    return "Cforall";
     48        case AutoGen.val:    return "autogenerated cfa";
     49        case Compiler.val:   return "compiler built-in";
     50        case BuiltinCFA.val: return "cfa built-in";
     51        case BuiltinC.val:   return "c built-in";
     52        default:             return "<unnamed linkage spec>";
    5553        }
     54}
    5655
    5756}
  • src/AST/LinkageSpec.hpp

    r92355883 r2a301ff  
    2525namespace Linkage {
    2626
    27         /// Bitflags for linkage specifiers
    28         enum {
    29                 Mangle       = 1 << 0,
    30                 Generate     = 1 << 1,
    31                 Overrideable = 1 << 2,
    32                 Builtin      = 1 << 3,
    33                 GccBuiltin   = 1 << 4
     27/// Bitflags for linkage specifiers
     28enum {
     29        Mangle       = 1 << 0,
     30        Generate     = 1 << 1,
     31        Overrideable = 1 << 2,
     32        Builtin      = 1 << 3,
     33        GccBuiltin   = 1 << 4
     34};
     35
     36/// Bitflag type for storage classes
     37struct 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                };
    3447        };
    3548
    36         /// Bitflag type for storage classes
    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                         };
    47                 };
     49        constexpr spec_flags( unsigned int val ) : val(val) {}
     50};
    4851
    49                 constexpr spec_flags( unsigned int val ) : val(val) {}
    50         };
     52using Spec = bitfield<spec_flags>;
    5153
    52         using Spec = bitfield<spec_flags>;
     54/// If `cmd` = "C" returns `spec` with `is_mangled = false`.
     55/// If `cmd` = "Cforall" returns `spec` with `is_mangled = true`.
     56Spec update( CodeLocation loc, Spec spec, const std::string * cmd );
    5357
    54         /// If `cmd` = "C" returns `spec` with `is_mangled = false`.
    55         /// If `cmd` = "Cforall" returns `spec` with `is_mangled = true`.
    56         Spec update( CodeLocation loc, Spec spec, const std::string * cmd );
     58/// A human-readable name for this spec
     59std::string name( Spec spec );
    5760
    58         /// A human-readable name for this spec
    59         std::string name( Spec spec );
     61// Pre-defined flag combinations
    6062
    61         // Pre-defined flag combinations
     63/// C built-in defined in prelude
     64constexpr Spec Intrinsic  = { Mangle | Generate | Overrideable | Builtin };
     65/// Ordinary Cforall
     66constexpr Spec Cforall    = { Mangle | Generate };
     67/// C code: not overloadable, not mangled
     68constexpr Spec C          = { Generate };
     69/// Built by translator (e.g. struct assignment)
     70constexpr Spec AutoGen    = { Mangle | Generate | Overrideable };
     71/// GCC internal
     72constexpr Spec Compiler   = { Mangle | Builtin | GccBuiltin };
     73/// Mangled builtins
     74constexpr Spec BuiltinCFA = { Mangle | Generate | Builtin };
     75/// Non-mangled builtins
     76constexpr Spec BuiltinC   = { Generate | Builtin };
    6277
    63         /// C built-in defined in prelude
    64         constexpr Spec Intrinsic  = { Mangle | Generate | Overrideable | Builtin };
    65         /// Ordinary Cforall
    66         constexpr Spec Cforall    = { Mangle | Generate };
    67         /// C code: not overloadable, not mangled
    68         constexpr Spec C          = { Generate };
    69         /// Built by translator (e.g. struct assignment)
    70         constexpr Spec AutoGen    = { Mangle | Generate | Overrideable };
    71         /// GCC internal
    72         constexpr Spec Compiler   = { Mangle | Builtin | GccBuiltin };
    73         /// Mangled builtins
    74         constexpr Spec BuiltinCFA = { Mangle | Generate | Builtin };
    75         /// Non-mangled builtins
    76         constexpr Spec BuiltinC   = { Generate | Builtin };
    7778}
    7879
  • src/AST/Pass.impl.hpp

    r92355883 r2a301ff  
    5353#endif
    5454
    55 namespace ast {
     55namespace ast::__pass {
     56        // Check if this is either a null pointer or a pointer to an empty container
     57        template<typename T>
     58        static inline bool empty( T * ptr ) {
     59                return !ptr || ptr->empty();
     60        }
     61
     62        template< typename core_t, typename node_t >
     63        static inline node_t* mutate(const node_t *node) {
     64                return std::is_base_of<PureVisitor, core_t>::value ? ::ast::shallowCopy(node) : ::ast::mutate(node);
     65        }
     66
     67        //------------------------------
     68        template<typename it_t, template <class...> class container_t>
     69        static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) {
     70                if ( empty( decls ) ) return;
     71
     72                std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto {
     73                                return new DeclStmt( decl->location, decl );
     74                        });
     75                decls->clear();
     76                if ( mutated ) *mutated = true;
     77        }
     78
     79        template<typename it_t, template <class...> class container_t>
     80        static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) {
     81                if ( empty( stmts ) ) return;
     82
     83                std::move(stmts->begin(), stmts->end(), it);
     84                stmts->clear();
     85                if ( mutated ) *mutated = true;
     86        }
     87
     88        //------------------------------
     89        /// Check if should be skipped, different for pointers and containers
    5690        template<typename node_t>
    57         node_t * shallowCopy( const node_t * node );
    58 
    59         namespace __pass {
    60                 // Check if this is either a null pointer or a pointer to an empty container
    61                 template<typename T>
    62                 static inline bool empty( T * ptr ) {
    63                         return !ptr || ptr->empty();
    64                 }
    65 
    66                 template< typename core_t, typename node_t >
    67                 static inline node_t* mutate(const node_t *node) {
    68                         return std::is_base_of<PureVisitor, core_t>::value ? ::ast::shallowCopy(node) : ::ast::mutate(node);
    69                 }
    70 
    71                 //------------------------------
    72                 template<typename it_t, template <class...> class container_t>
    73                 static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) {
    74                         if ( empty( decls ) ) return;
    75 
    76                         std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto {
    77                                         return new DeclStmt( decl->location, decl );
    78                                 });
    79                         decls->clear();
    80                         if ( mutated ) *mutated = true;
    81                 }
    82 
    83                 template<typename it_t, template <class...> class container_t>
    84                 static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) {
    85                         if ( empty( stmts ) ) return;
    86 
    87                         std::move(stmts->begin(), stmts->end(), it);
    88                         stmts->clear();
    89                         if ( mutated ) *mutated = true;
    90                 }
    91 
    92                 //------------------------------
    93                 /// Check if should be skipped, different for pointers and containers
    94                 template<typename node_t>
    95                 bool skip( const ast::ptr<node_t> & val ) {
    96                         return !val;
    97                 }
    98 
    99                 template< template <class...> class container_t, typename node_t >
    100                 bool skip( const container_t<ast::ptr< node_t >> & val ) {
    101                         return val.empty();
    102                 }
    103 
    104                 //------------------------------
    105                 /// Get the value to visit, different for pointers and containers
    106                 template<typename node_t>
    107                 auto get( const ast::ptr<node_t> & val, int ) -> decltype(val.get()) {
    108                         return val.get();
    109                 }
    110 
    111                 template<typename node_t>
    112                 const node_t & get( const node_t & val, long ) {
    113                         return val;
    114                 }
    115 
    116                 //------------------------------
    117                 /// Check if value was mutated, different for pointers and containers
    118                 template<typename lhs_t, typename rhs_t>
    119                 bool differs( const lhs_t * old_val, const rhs_t * new_val ) {
    120                         return old_val != new_val;
    121                 }
    122 
    123                 template< template <class...> class container_t, typename node_t >
    124                 bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) {
    125                         return !new_val.empty();
    126                 }
     91        bool skip( const ast::ptr<node_t> & val ) {
     92                return !val;
     93        }
     94
     95        template< template <class...> class container_t, typename node_t >
     96        bool skip( const container_t<ast::ptr< node_t >> & val ) {
     97                return val.empty();
     98        }
     99
     100        //------------------------------
     101        /// Get the value to visit, different for pointers and containers
     102        template<typename node_t>
     103        auto get( const ast::ptr<node_t> & val, int ) -> decltype(val.get()) {
     104                return val.get();
     105        }
     106
     107        template<typename node_t>
     108        const node_t & get( const node_t & val, long ) {
     109                return val;
     110        }
     111
     112        //------------------------------
     113        /// Check if value was mutated, different for pointers and containers
     114        template<typename lhs_t, typename rhs_t>
     115        bool differs( const lhs_t * old_val, const rhs_t * new_val ) {
     116                return old_val != new_val;
     117        }
     118
     119        template< template <class...> class container_t, typename node_t >
     120        bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) {
     121                return !new_val.empty();
    127122        }
    128123}
     
    19201915        VISIT_START( node );
    19211916
    1922         __pass::symtab::addStruct( core, 0, node->name );
     1917        __pass::symtab::addStructId( core, 0, node->name );
    19231918
    19241919        if ( __visit_children() ) {
     
    19361931        VISIT_START( node );
    19371932
    1938         __pass::symtab::addUnion( core, 0, node->name );
     1933        __pass::symtab::addUnionId( core, 0, node->name );
    19391934
    19401935        if ( __visit_children() ) {
  • src/AST/Pass.proto.hpp

    r92355883 r2a301ff  
    488488
    489489        template<typename core_t>
    490         static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
     490        static inline auto addStructId( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStructId( str ), void() ) {
    491491                if ( ! core.symtab.lookupStruct( str ) ) {
    492                         core.symtab.addStruct( str );
    493                 }
    494         }
    495 
    496         template<typename core_t>
    497         static inline void addStruct( core_t &, long, const std::string & ) {}
    498 
    499         template<typename core_t>
    500         static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
     492                        core.symtab.addStructId( str );
     493                }
     494        }
     495
     496        template<typename core_t>
     497        static inline void addStructId( core_t &, long, const std::string & ) {}
     498
     499        template<typename core_t>
     500        static inline auto addUnionId( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnionId( str ), void() ) {
    501501                if ( ! core.symtab.lookupUnion( str ) ) {
    502                         core.symtab.addUnion( str );
    503                 }
    504         }
    505 
    506         template<typename core_t>
    507         static inline void addUnion( core_t &, long, const std::string & ) {}
     502                        core.symtab.addUnionId( str );
     503                }
     504        }
     505
     506        template<typename core_t>
     507        static inline void addUnionId( core_t &, long, const std::string & ) {}
    508508
    509509        #undef SYMTAB_FUNC1
  • src/AST/SymbolTable.cpp

    r92355883 r2a301ff  
    1919
    2020#include "Copy.hpp"
    21 #include <iostream>
    22 #include <algorithm>
    23 
    2421#include "Decl.hpp"
    2522#include "Expr.hpp"
     
    206203                        out.push_back(decl.second);
    207204                }
    208 
    209                 // std::cerr << otypeKey << ' ' << out.size() << std::endl;
    210205        }
    211206
     
    328323}
    329324
    330 void SymbolTable::addStruct( const std::string &id ) {
     325void SymbolTable::addStructId( const std::string &id ) {
    331326        addStruct( new StructDecl( CodeLocation(), id ) );
    332327}
     
    370365}
    371366
    372 void SymbolTable::addUnion( const std::string &id ) {
     367void SymbolTable::addUnionId( const std::string &id ) {
    373368        addUnion( new UnionDecl( CodeLocation(), id ) );
    374369}
  • src/AST/SymbolTable.hpp

    r92355883 r2a301ff  
    150150        void addType( const NamedTypeDecl * decl );
    151151        /// Adds a struct declaration to the symbol table by name
    152         void addStruct( const std::string & id );
     152        void addStructId( const std::string & id );
    153153        /// Adds a struct declaration to the symbol table
    154154        void addStruct( const StructDecl * decl );
     
    156156        void addEnum( const EnumDecl * decl );
    157157        /// Adds a union declaration to the symbol table by name
    158         void addUnion( const std::string & id );
     158        void addUnionId( const std::string & id );
    159159        /// Adds a union declaration to the symbol table
    160160        void addUnion( const UnionDecl * decl );
  • src/AST/Util.cpp

    r92355883 r2a301ff  
    2020#include "Pass.hpp"
    2121#include "TranslationUnit.hpp"
     22#include "Common/utility.h"
     23#include "GenPoly/ScopedSet.h"
    2224
    2325#include <vector>
     26
     27using GenPoly::ScopedSet;
    2428
    2529namespace ast {
     
    102106}
    103107
     108/// Check for Floating Nodes:
     109/// Every node should be reachable from a root (the TranslationUnit) via a
     110/// chain of structural references (tracked with ptr). This cannot check all
     111/// of that, it just checks if a given node's field has a strong reference.
     112template<typename node_t, typename field_t>
     113void noFloatingNode( const node_t * node, field_t node_t::*field_ptr ) {
     114        const field_t & field = node->*field_ptr;
     115        if ( nullptr == field ) return;
     116        assertf( field->isManaged(), "Floating node found." );
     117}
     118
    104119struct InvariantCore {
    105120        // To save on the number of visits: this is a kind of composed core.
     
    127142        }
    128143
     144        void previsit( const VariableExpr * node ) {
     145                previsit( (const ParseNode *)node );
     146                noFloatingNode( node, &VariableExpr::var );
     147        }
     148
    129149        void previsit( const MemberExpr * node ) {
    130150                previsit( (const ParseNode *)node );
     
    132152        }
    133153
     154        void previsit( const StructInstType * node ) {
     155                previsit( (const Node *)node );
     156                noFloatingNode( node, &StructInstType::base );
     157        }
     158
     159        void previsit( const UnionInstType * node ) {
     160                previsit( (const Node *)node );
     161                noFloatingNode( node, &UnionInstType::base );
     162        }
     163
     164        void previsit( const EnumInstType * node ) {
     165                previsit( (const Node *)node );
     166                noFloatingNode( node, &EnumInstType::base );
     167        }
     168
     169        void previsit( const TypeInstType * node ) {
     170                previsit( (const Node *)node );
     171                noFloatingNode( node, &TypeInstType::base );
     172        }
     173
    134174        void postvisit( const Node * node ) {
    135175                no_strong_cycles.postvisit( node );
     
    137177};
    138178
     179/// Checks that referred to nodes are in scope.
     180/// This checks many readonly pointers to see if the declaration they are
     181/// referring to is in scope by the structural rules of code.
     182// Any escapes marked with a bug should be removed once the bug is fixed.
     183struct InScopeCore : public ast::WithShortCircuiting {
     184        ScopedSet<DeclWithType const *> typedDecls;
     185        ScopedSet<TypeDecl const *> typeDecls;
     186        // These 3 are really hard to check, because uses that originally ref. at
     187        // a forward declaration can be rewired to point a later full definition.
     188        ScopedSet<StructDecl const *> structDecls;
     189        ScopedSet<UnionDecl const *> unionDecls;
     190        ScopedSet<EnumDecl const *> enumDecls;
     191        ScopedSet<TraitDecl const *> traitDecls;
     192
     193        bool isInGlobal = false;
     194
     195        void beginScope() {
     196                typedDecls.beginScope();
     197                typeDecls.beginScope();
     198                structDecls.beginScope();
     199                unionDecls.beginScope();
     200                enumDecls.beginScope();
     201                traitDecls.beginScope();
     202        }
     203
     204        void endScope() {
     205                typedDecls.endScope();
     206                typeDecls.endScope();
     207                structDecls.endScope();
     208                unionDecls.endScope();
     209                enumDecls.endScope();
     210                traitDecls.endScope();
     211        }
     212
     213        void previsit( ApplicationExpr const * expr ) {
     214                // All isInGlobal manipulation is just to isolate this check.
     215                // The invalid compound literals lead to bad ctor/dtors. [#280]
     216                VariableExpr const * func = nullptr;
     217                CastExpr const * cast = nullptr;
     218                VariableExpr const * arg = nullptr;
     219                if ( isInGlobal
     220                                && 1 == expr->args.size()
     221                                && ( func = expr->func.as<VariableExpr>() )
     222                                && ( "?{}" == func->var->name || "^?{}" == func->var->name )
     223                                && ( cast = expr->args[0].as<CastExpr>() )
     224                                && ( arg = cast->arg.as<VariableExpr>() )
     225                                && isPrefix( arg->var->name, "_compLit" ) ) {
     226                        visit_children = false;
     227                }
     228        }
     229
     230        void previsit( VariableExpr const * expr ) {
     231                if ( !expr->var ) return;
     232                // bitwise assignment escape [#281]
     233                if ( expr->var->location.isUnset() ) return;
     234                assert( typedDecls.contains( expr->var ) );
     235        }
     236
     237        void previsit( FunctionType const * type ) {
     238                // This is to avoid checking the assertions, which can point at the
     239                // function's declaration and not the enclosing function.
     240                for ( auto type_param : type->forall ) {
     241                        if ( type_param->formal_usage ) {
     242                                visit_children = false;
     243                                // We could check non-assertion fields here.
     244                        }
     245                }
     246        }
     247
     248        void previsit( TypeInstType const * type ) {
     249                if ( !type->base ) return;
     250                assertf( type->base->isManaged(), "Floating Node" );
     251
     252                // bitwise assignment escape [#281]
     253                if ( type->base->location.isUnset() ) return;
     254                // Formal types can actually look at out of scope variables.
     255                if ( type->formal_usage ) return;
     256                assert( typeDecls.contains( type->base ) );
     257        }
     258
     259        void previsit( TraitInstType const * type ) {
     260                if ( !type->base ) return;
     261                assert( traitDecls.contains( type->base ) );
     262        }
     263
     264        void previsit( ObjectDecl const * decl ) {
     265                typedDecls.insert( decl );
     266                // There are some ill-formed compound literals. [#280]
     267                // The only known problem cases are at the top level.
     268                if ( isPrefix( decl->name, "_compLit" ) ) {
     269                        visit_children = false;
     270                }
     271        }
     272
     273        void previsit( FunctionDecl const * decl ) {
     274                typedDecls.insert( decl );
     275                beginScope();
     276                for ( auto & type_param : decl->type_params ) {
     277                        typeDecls.insert( type_param );
     278                }
     279                for ( auto & assertion : decl->assertions ) {
     280                        typedDecls.insert( assertion );
     281                }
     282                for ( auto & param : decl->params ) {
     283                        typedDecls.insert( param );
     284                }
     285                for ( auto & ret : decl->returns ) {
     286                        typedDecls.insert( ret );
     287                }
     288                // No special handling of withExprs.
     289
     290                // Part of the compound literal escape. [#280]
     291                if ( "__global_init__" == decl->name
     292                                || "__global_destroy__" == decl->name ) {
     293                        assert( !isInGlobal );
     294                        isInGlobal = true;
     295                }
     296        }
     297
     298        void postvisit( FunctionDecl const * decl ) {
     299                endScope();
     300                // Part of the compound literal escape. [#280]
     301                if ( isInGlobal && ( "__global_init__" == decl->name
     302                                || "__global_destroy__" == decl->name ) ) {
     303                        isInGlobal = false;
     304                }
     305        }
     306
     307        void previsit( StructDecl const * decl ) {
     308                structDecls.insert( decl );
     309                beginScope();
     310                for ( auto & type_param : decl->params ) {
     311                        typeDecls.insert( type_param );
     312                }
     313        }
     314
     315        void postvisit( StructDecl const * ) {
     316                endScope();
     317        }
     318
     319        void previsit( UnionDecl const * decl ) {
     320                unionDecls.insert( decl );
     321                beginScope();
     322                for ( auto & type_param : decl->params ) {
     323                        typeDecls.insert( type_param );
     324                }
     325        }
     326
     327        void postvisit( UnionDecl const * ) {
     328                endScope();
     329        }
     330
     331        void previsit( EnumDecl const * decl ) {
     332                enumDecls.insert( decl );
     333                if ( ast::EnumDecl::EnumHiding::Visible == decl->hide ) {
     334                        for ( auto & member : decl->members ) {
     335                                typedDecls.insert( member.strict_as<ast::DeclWithType>() );
     336                        }
     337                }
     338                beginScope();
     339                for ( auto & type_param : decl->params ) {
     340                        typeDecls.insert( type_param );
     341                }
     342        }
     343
     344        void postvisit( EnumDecl const * ) {
     345                endScope();
     346        }
     347
     348        void previsit( TraitDecl const * decl ) {
     349                traitDecls.insert( decl );
     350                beginScope();
     351                for ( auto & type_param : decl->params ) {
     352                        typeDecls.insert( type_param );
     353                }
     354        }
     355
     356        void postvisit( TraitDecl const * ) {
     357                endScope();
     358        }
     359
     360        void previsit( Designation const * ) {
     361                visit_children = false;
     362        }
     363};
     364
    139365} // namespace
    140366
    141367void checkInvariants( TranslationUnit & transUnit ) {
    142         ast::Pass<InvariantCore>::run( transUnit );
     368        Pass<InvariantCore>::run( transUnit );
     369        Pass<InScopeCore>::run( transUnit );
    143370}
    144371
  • src/Common/ScopedMap.h

    r92355883 r2a301ff  
    199199        friend class ScopedMap;
    200200        friend class const_iterator;
    201         typedef typename ScopedMap::MapType::iterator wrapped_iterator;
    202         typedef typename ScopedMap::ScopeList scope_list;
    203         typedef typename scope_list::size_type size_type;
     201        typedef typename MapType::iterator wrapped_iterator;
     202        typedef typename ScopeList::size_type size_type;
    204203
    205204        /// Checks if this iterator points to a valid item
     
    220219        }
    221220
    222         iterator(scope_list & _scopes, const wrapped_iterator & _it, size_type inLevel)
     221        iterator(ScopeList & _scopes, const wrapped_iterator & _it, size_type inLevel)
    223222                : scopes(&_scopes), it(_it), level(inLevel) {}
    224223public:
     
    266265
    267266private:
    268         scope_list *scopes;
     267        ScopeList *scopes;
    269268        wrapped_iterator it;
    270269        size_type level;
  • src/Concurrency/KeywordsNew.cpp

    r92355883 r2a301ff  
    534534void ConcurrentSueKeyword::addGetRoutines(
    535535                const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) {
     536        // Clone the signature and then build the body.
     537        ast::FunctionDecl * decl = ast::deepCopy( forward );
     538
    536539        // Say it is generated at the "same" places as the forward declaration.
    537         const CodeLocation & location = forward->location;
    538 
    539         const ast::DeclWithType * param = forward->params.front();
     540        const CodeLocation & location = decl->location;
     541
     542        const ast::DeclWithType * param = decl->params.front();
    540543        ast::Stmt * stmt = new ast::ReturnStmt( location,
    541544                new ast::AddressExpr( location,
     
    551554        );
    552555
    553         ast::FunctionDecl * decl = ast::deepCopy( forward );
    554556        decl->stmts = new ast::CompoundStmt( location, { stmt } );
    555557        declsToAddAfter.push_back( decl );
     
    12361238}
    12371239
     1240void flattenTuple( const ast::UntypedTupleExpr * tuple, std::vector<ast::ptr<ast::Expr>> & output ) {
     1241    for ( auto & expr : tuple->exprs ) {
     1242        const ast::UntypedTupleExpr * innerTuple = dynamic_cast<const ast::UntypedTupleExpr *>(expr.get());
     1243        if ( innerTuple ) flattenTuple( innerTuple, output );
     1244        else output.emplace_back( ast::deepCopy( expr ));
     1245    }
     1246}
     1247
    12381248ast::CompoundStmt * MutexKeyword::addStatements(
    12391249                const ast::CompoundStmt * body,
     
    12481258        // std::string lockFnName = mutex_func_namer.newName();
    12491259        // std::string unlockFnName = mutex_func_namer.newName();
     1260
     1261    // If any arguments to the mutex stmt are tuples, flatten them
     1262    std::vector<ast::ptr<ast::Expr>> flattenedArgs;
     1263    for ( auto & arg : args ) {
     1264        const ast::UntypedTupleExpr * tuple = dynamic_cast<const ast::UntypedTupleExpr *>(args.at(0).get());
     1265        if ( tuple ) flattenTuple( tuple, flattenedArgs );
     1266        else flattenedArgs.emplace_back( ast::deepCopy( arg ));
     1267    }
    12501268
    12511269        // Make pointer to the monitors.
     
    12571275                                new ast::VoidType()
    12581276                        ),
    1259                         ast::ConstantExpr::from_ulong( location, args.size() ),
     1277                        ast::ConstantExpr::from_ulong( location, flattenedArgs.size() ),
    12601278                        ast::FixedLen,
    12611279                        ast::DynamicDim
     
    12641282                        location,
    12651283                        map_range<std::vector<ast::ptr<ast::Init>>>(
    1266                                 args, [](const ast::Expr * expr) {
     1284                                flattenedArgs, [](const ast::Expr * expr) {
    12671285                                        return new ast::SingleInit(
    12681286                                                expr->location,
     
    12871305
    12881306        // adds a nested try stmt for each lock we are locking
    1289         for ( long unsigned int i = 0; i < args.size(); i++ ) {
     1307        for ( long unsigned int i = 0; i < flattenedArgs.size(); i++ ) {
    12901308                ast::UntypedExpr * innerAccess = new ast::UntypedExpr(
    12911309                        location,
     
    12981316                // make the try body
    12991317                ast::CompoundStmt * currTryBody = new ast::CompoundStmt( location );
    1300                 ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", args, location, innerAccess );
     1318                ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", flattenedArgs, location, innerAccess );
    13011319                currTryBody->push_back( lockCall );
    13021320
    13031321                // make the finally stmt
    13041322                ast::CompoundStmt * currFinallyBody = new ast::CompoundStmt( location );
    1305                 ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", args, location, innerAccess );
     1323                ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", flattenedArgs, location, innerAccess );
    13061324                currFinallyBody->push_back( unlockCall );
    13071325
     
    13431361                                                new ast::SingleInit(
    13441362                                                        location,
    1345                                                         ast::ConstantExpr::from_ulong( location, args.size() ) ),
     1363                                                        ast::ConstantExpr::from_ulong( location, flattenedArgs.size() ) ),
    13461364                                        },
    13471365                                        {},
  • src/Concurrency/Waituntil.cpp

    r92355883 r2a301ff  
    142142    UniqueName namer_target = "__clause_target_"s;
    143143    UniqueName namer_when = "__when_cond_"s;
     144    UniqueName namer_label = "__waituntil_label_"s;
    144145
    145146    string idxName = "__CFA_clause_idx_";
     
    173174    void addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName );
    174175    void setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body );
    175     ForStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );
     176    CompoundStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );
    176177    Expr * genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName );
    177178    CompoundStmt * genStmtBlock( const WhenClause * clause, const ClauseData * data );
    178179    Stmt * genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData );
    179     Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & satName, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );
     180    Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );
    180181    void genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName );
    181182    Stmt * recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName );
     
    626627    return new CompoundStmt( cLoc,
    627628        {
    628             new ExprStmt( cLoc,
    629                 genSelectTraitCall( clause, data, "on_selected" )
    630             ),
    631             ast::deepCopy( clause->stmt )
     629            new IfStmt( cLoc,
     630                genSelectTraitCall( clause, data, "on_selected" ),
     631                ast::deepCopy( clause->stmt )
     632            )
    632633        }
    633634    );
     
    653654    }
    654655}*/
    655 ForStmt * GenerateWaitUntilCore::genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ) {
     656CompoundStmt * GenerateWaitUntilCore::genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ) {
    656657    CompoundStmt * ifBody = new CompoundStmt( stmt->location );
    657658    const CodeLocation & loc = stmt->location;
     659
     660    string switchLabel = namer_label.newName();
    658661
    659662    /* generates:
     
    707710                                )
    708711                            ),
    709                             new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc ) )
     712                            new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) )
    710713                        }
    711714                    )
     
    719722        new SwitchStmt( loc,
    720723            new NameExpr( loc, idxName ),
    721             std::move( switchCases )
     724            std::move( switchCases ),
     725            { Label( loc, switchLabel ) }
    722726        )
    723727    );
     
    744748    );
    745749
    746     return new ForStmt( loc,
     750    string forLabel = namer_label.newName();
     751
     752    // we hoist init here so that this pass can happen after hoistdecls pass
     753    return new CompoundStmt( loc,
    747754        {
    748755            new DeclStmt( loc,
     
    752759                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    753760                )
    754             )
    755         },  // inits
    756         new UntypedExpr ( loc,
    757             new NameExpr( loc, "?<?" ),
    758             {
    759                 new NameExpr( loc, idxName ),
    760                 ConstantExpr::from_int( loc, stmt->clauses.size() )
    761             }
    762         ),  // cond
    763         new UntypedExpr ( loc,
    764             new NameExpr( loc, "?++" ),
    765             { new NameExpr( loc, idxName ) }
    766         ),  // inc
    767         new CompoundStmt( loc,
    768             {
    769                 new IfStmt( loc,
    770                     new UntypedExpr ( loc,
    771                         new NameExpr( loc, predName ),
    772                         { new NameExpr( loc, clauseData.at(0)->statusName ) }
    773                     ),
    774                     new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc ) )
    775                 ),
    776                 ifSwitch
    777             }
    778         )   // body
     761            ),
     762            new ForStmt( loc,
     763                {},  // inits
     764                new UntypedExpr ( loc,
     765                    new NameExpr( loc, "?<?" ),
     766                    {
     767                        new NameExpr( loc, idxName ),
     768                        ConstantExpr::from_int( loc, stmt->clauses.size() )
     769                    }
     770                ),  // cond
     771                new UntypedExpr ( loc,
     772                    new NameExpr( loc, "?++" ),
     773                    { new NameExpr( loc, idxName ) }
     774                ),  // inc
     775                new CompoundStmt( loc,
     776                    {
     777                        new IfStmt( loc,
     778                            new UntypedExpr ( loc,
     779                                new NameExpr( loc, predName ),
     780                                { new NameExpr( loc, clauseData.at(0)->statusName ) }
     781                            ),
     782                            new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) )
     783                        ),
     784                        ifSwitch
     785                    }
     786                ),   // body
     787                { Label( loc, forLabel ) }
     788            )
     789        }
    779790    );
    780791}
     
    809820}
    810821
    811 Stmt * GenerateWaitUntilCore::genNoElseClauseBranch( const WaitUntilStmt * stmt, string & satName, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ) {
     822Stmt * GenerateWaitUntilCore::genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ) {
    812823    CompoundStmt * whileBody = new CompoundStmt( stmt->location );
    813824    const CodeLocation & loc = stmt->location;
     
    823834    );
    824835
    825     whileBody->push_back( genStatusCheckFor( stmt, clauseData, satName ) );
     836    whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) );
    826837
    827838    return new CompoundStmt( loc,
    828839        {
    829840            new WhileDoStmt( loc,
    830                 genNotSatExpr( stmt, satName, arrName ),
     841                genNotSatExpr( stmt, runName, arrName ),
    831842                whileBody,  // body
    832843                {}          // no inits
    833             ),
    834             genStatusCheckFor( stmt, clauseData, runName )
     844            )
    835845        }
    836846    );
     
    856866                new ObjectDecl( cLoc,
    857867                    currClause->targetName,
    858                     new ReferenceType( new TypeofType( ast::deepCopy( stmt->clauses.at(i)->target ) ) ),
     868                    new ReferenceType(
     869                        new TypeofType( new UntypedExpr( cLoc,
     870                            new NameExpr( cLoc, "__CFA_select_get_type" ),
     871                            { ast::deepCopy( stmt->clauses.at(i)->target ) }
     872                        ))
     873                    ),
    859874                    new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) )
    860875                )
     
    12681283                new NameExpr( stmt->else_cond->location, elseWhenName ),
    12691284                genElseClauseBranch( stmt, runName, statusArrName, clauseData ),
    1270                 genNoElseClauseBranch( stmt, satName, runName, statusArrName, pCountName, clauseData )
     1285                genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData )
    12711286            )
    12721287        );
    12731288    } else if ( !stmt->else_stmt ) { // normal gen
    1274         tryBody->push_back( genNoElseClauseBranch( stmt, satName, runName, statusArrName, pCountName, clauseData ) );
     1289        tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) );
    12751290    } else { // generate just else
    12761291        tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) );
    12771292    }
    12781293
     1294    // Collection of unregister calls on resources to be put in finally clause
     1295    // for each clause:
     1296    // if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
     1297    // OR if when( ... ) defined on resource
     1298    // if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
    12791299    CompoundStmt * unregisters = new CompoundStmt( loc );
    1280     // generates for each clause:
    1281     // if ( !has_run( clause_statuses[i] ) )
    1282     // OR if when_cond defined
    1283     // if ( when_cond_i && !has_run( clause_statuses[i] ) )
    1284     // body of if is:
    1285     // { if (unregister_select(A, clause1) && on_selected(A, clause1)) clause1->stmt; } // this conditionally runs the block unregister_select returns true (needed by some primitives)
    1286     Expr * ifCond;
    1287     UntypedExpr * statusExpr; // !clause_statuses[i]
     1300
     1301    Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] )
    12881302    for ( int i = 0; i < numClauses; i++ ) {
    12891303        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    12901304
     1305        // Generates: !__CFA_has_clause_run( clause_statuses[i] )
    12911306        statusExpr = new UntypedExpr ( cLoc,
    12921307            new NameExpr( cLoc, "!?" ),
     
    13001315            }
    13011316        );
    1302 
    1303         if ( stmt->clauses.at(i)->when_cond ) {
    1304             // generates: if( when_cond_i && !has_run(clause_statuses[i]) )
    1305             ifCond = new LogicalExpr( cLoc,
     1317       
     1318        // Generates:
     1319        // (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
     1320        statusExpr = new LogicalExpr( cLoc,
     1321            new CastExpr( cLoc,
     1322                statusExpr,
     1323                new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast
     1324            ),
     1325            new CastExpr( cLoc,
     1326                genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
     1327                new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast
     1328            ),
     1329            LogicalFlag::AndExpr
     1330        );
     1331       
     1332        // if when cond defined generates:
     1333        // when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
     1334        if ( stmt->clauses.at(i)->when_cond )
     1335            statusExpr = new LogicalExpr( cLoc,
    13061336                new CastExpr( cLoc,
    13071337                    new NameExpr( cLoc, clauseData.at(i)->whenName ),
     
    13141344                LogicalFlag::AndExpr
    13151345            );
    1316         } else // generates: if( !clause_statuses[i] )
    1317             ifCond = statusExpr;
    1318        
     1346
     1347        // generates:
     1348        // if ( statusExpr ) { ... clausei stmt ... }
    13191349        unregisters->push_back(
    13201350            new IfStmt( cLoc,
    1321                 ifCond,
     1351                statusExpr,
    13221352                new CompoundStmt( cLoc,
    13231353                    {
    13241354                        new IfStmt( cLoc,
    1325                             genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
    1326                             // ast::deepCopy( stmt->clauses.at(i)->stmt )
    1327                             genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
     1355                            genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
     1356                            ast::deepCopy( stmt->clauses.at(i)->stmt )
    13281357                        )
    13291358                    }
    13301359                )
    1331                
    1332             )
    1333         );
     1360            )
     1361        );
     1362
     1363        // // generates:
     1364        // // if ( statusExpr ) { ... clausei stmt ... }
     1365        // unregisters->push_back(
     1366        //     new IfStmt( cLoc,
     1367        //         statusExpr,
     1368        //         genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
     1369        //     )
     1370        // );
    13341371    }
    13351372
  • src/ControlStruct/ExceptDeclNew.cpp

    r92355883 r2a301ff  
    242242}
    243243
    244 ast::ObjectDecl const * createExternVTable(
     244ast::ObjectDecl * createExternVTable(
    245245                CodeLocation const & location,
    246246                std::string const & exceptionName,
     
    299299                } ),
    300300                ast::Storage::Classes(),
    301                 ast::Linkage::Cforall
     301                ast::Linkage::Cforall,
     302                { new ast::Attribute( "cfa_linkonce" ) }
    302303        );
    303304}
     
    352353                } ),
    353354                ast::Storage::Classes(),
    354                 ast::Linkage::Cforall
    355         );
    356 }
    357 
    358 ast::ObjectDecl const * createVirtualTable(
     355                ast::Linkage::Cforall,
     356                { new ast::Attribute( "cfa_linkonce" ) }
     357        );
     358}
     359
     360ast::ObjectDecl * createVirtualTable(
    359361                CodeLocation const & location,
    360362                std::string const & exceptionName,
     
    451453        std::string const & tableName = decl->name;
    452454
     455        ast::ObjectDecl * retDecl;
    453456        if ( decl->storage.is_extern ) {
    454457                // Unique type-ids are only needed for polymorphic instances.
     
    457460                                createExternTypeId( location, exceptionName, params ) );
    458461                }
    459                 return createExternVTable( location, exceptionName, params, tableName );
     462                retDecl = createExternVTable( location, exceptionName, params, tableName );
    460463        } else {
    461464                // Unique type-ids are only needed for polymorphic instances.
     
    468471                declsToAddBefore.push_back(
    469472                        createMsg( location, exceptionName, params ) );
    470                 return createVirtualTable(
     473                retDecl = createVirtualTable(
    471474                        location, exceptionName, params, tableName );
    472475        }
     476
     477        for ( ast::ptr<ast::Attribute> const & attr : decl->attributes ) {
     478                retDecl->attributes.push_back( attr );
     479        }
     480
     481        return retDecl;
    473482}
    474483
     
    478487
    479488                std::string vtableName = Virtual::vtableTypeName( inst->name );
     489
    480490                auto newType = new ast::StructInstType( vtableName );
    481491                for ( ast::ptr<ast::Expr> const & param : inst->params ) {
  • src/GenPoly/Box.cc

    r92355883 r2a301ff  
    15381538                }
    15391539
     1540                /// Checks if memberDecl matches the decl from an aggregate.
     1541                bool isMember( DeclarationWithType *memberDecl, Declaration * decl ) {
     1542                        if ( memberDecl->get_name() != decl->get_name() )
     1543                                return false;
     1544
     1545                        if ( memberDecl->get_name().empty() ) {
     1546                                // Plan-9 Field: match on unique_id.
     1547                                return ( memberDecl->get_uniqueId() == decl->get_uniqueId() );
     1548                        }
     1549
     1550                        DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl );
     1551
     1552                        if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) {
     1553                                // Tuple-Element Field: expect neither had mangled name; accept match on simple name (like field_2) only.
     1554                                assert( memberDecl->get_mangleName().empty() && declWithType->get_mangleName().empty() );
     1555                                return true;
     1556                        }
     1557
     1558                        // Ordinary Field: Use full name to accommodate overloading.
     1559                        return ( memberDecl->get_mangleName() == declWithType->get_mangleName() );
     1560                }
     1561
    15401562                /// Finds the member in the base list that matches the given declaration; returns its index, or -1 if not present
    15411563                long findMember( DeclarationWithType *memberDecl, std::list< Declaration* > &baseDecls ) {
    15421564                        for ( auto pair : enumerate( baseDecls ) ) {
    1543                                 Declaration * decl = pair.val;
    1544                                 size_t i = pair.idx;
    1545                                 if ( memberDecl->get_name() != decl->get_name() )
    1546                                         continue;
    1547 
    1548                                 if ( memberDecl->get_name().empty() ) {
    1549                                         // plan-9 field: match on unique_id
    1550                                         if ( memberDecl->get_uniqueId() == decl->get_uniqueId() )
    1551                                                 return i;
    1552                                         else
    1553                                                 continue;
    1554                                 }
    1555 
    1556                                 DeclarationWithType *declWithType = strict_dynamic_cast< DeclarationWithType* >( decl );
    1557 
    1558                                 if ( memberDecl->get_mangleName().empty() || declWithType->get_mangleName().empty() ) {
    1559                                         // tuple-element field: expect neither had mangled name; accept match on simple name (like field_2) only
    1560                                         assert( memberDecl->get_mangleName().empty() && declWithType->get_mangleName().empty() );
    1561                                         return i;
    1562                                 }
    1563 
    1564                                 // ordinary field: use full name to accommodate overloading
    1565                                 if ( memberDecl->get_mangleName() == declWithType->get_mangleName() )
    1566                                         return i;
    1567                                 else
    1568                                         continue;
     1565                                if ( isMember( memberDecl, pair.val ) ) {
     1566                                        return pair.idx;
     1567                                }
    15691568                        }
    15701569                        return -1;
  • src/GenPoly/ErasableScopedMap.h

    r92355883 r2a301ff  
    5757        /// Starts a new scope
    5858        void beginScope() {
    59                 Scope scope;
    60                 scopes.push_back(scope);
     59                scopes.emplace_back();
    6160        }
    6261
     
    145144                public std::iterator< std::bidirectional_iterator_tag, value_type > {
    146145        friend class ErasableScopedMap;
    147         typedef typename std::map< Key, Value >::iterator wrapped_iterator;
    148         typedef typename std::vector< std::map< Key, Value > > scope_list;
    149         typedef typename scope_list::size_type size_type;
     146        typedef typename Scope::iterator wrapped_iterator;
     147        typedef typename ScopeList::size_type size_type;
    150148
    151149        /// Checks if this iterator points to a valid item
  • src/GenPoly/ScopedSet.h

    r92355883 r2a301ff  
    4747        /// Starts a new scope
    4848        void beginScope() {
    49                 Scope scope;
    50                 scopes.push_back(scope);
     49                scopes.emplace_back();
    5150        }
    5251
     
    8584        iterator findNext( const_iterator &it, const Value &key ) {
    8685                if ( it.i == 0 ) return end();
    87                         for ( size_type i = it.i - 1; ; --i ) {
     86                for ( size_type i = it.i - 1; ; --i ) {
    8887                        typename Scope::iterator val = scopes[i].find( key );
    8988                        if ( val != scopes[i].end() ) return iterator( scopes, val, i );
     
    112111        friend class ScopedSet;
    113112        friend class const_iterator;
    114         typedef typename std::set< Value >::iterator wrapped_iterator;
    115         typedef typename std::vector< std::set< Value > > scope_list;
    116         typedef typename scope_list::size_type size_type;
     113        typedef typename Scope::iterator wrapped_iterator;
     114        typedef typename ScopeList::size_type size_type;
    117115
    118116        /// Checks if this iterator points to a valid item
     
    133131        }
    134132
    135         iterator(scope_list const &_scopes, const wrapped_iterator &_it, size_type _i)
     133        iterator(ScopeList const &_scopes, const wrapped_iterator &_it, size_type _i)
    136134                : scopes(&_scopes), it(_it), i(_i) {}
    137135public:
     
    176174
    177175private:
    178         scope_list const *scopes;
     176        ScopeList const *scopes;
    179177        wrapped_iterator it;
    180178        size_type i;
     
    185183                public std::iterator< std::bidirectional_iterator_tag, value_type > {
    186184        friend class ScopedSet;
    187         typedef typename std::set< Value >::iterator wrapped_iterator;
    188         typedef typename std::set< Value >::const_iterator wrapped_const_iterator;
    189         typedef typename std::vector< std::set< Value > > scope_list;
    190         typedef typename scope_list::size_type size_type;
     185        typedef typename Scope::iterator wrapped_iterator;
     186        typedef typename Scope::const_iterator wrapped_const_iterator;
     187        typedef typename ScopeList::size_type size_type;
    191188
    192189        /// Checks if this iterator points to a valid item
     
    207204        }
    208205
    209         const_iterator(scope_list const &_scopes, const wrapped_const_iterator &_it, size_type _i)
     206        const_iterator(ScopeList const &_scopes, const wrapped_const_iterator &_it, size_type _i)
    210207                : scopes(&_scopes), it(_it), i(_i) {}
    211208public:
     
    255252
    256253private:
    257         scope_list const *scopes;
     254        ScopeList const *scopes;
    258255        wrapped_const_iterator it;
    259256        size_type i;
  • src/GenPoly/SpecializeNew.cpp

    r92355883 r2a301ff  
    104104
    105105bool needsPolySpecialization(
    106                 const ast::Type * formalType,
     106                const ast::Type * /*formalType*/,
    107107                const ast::Type * actualType,
    108108                const ast::TypeSubstitution * subs ) {
     
    126126                        if ( closedVars.find( *inst ) == closedVars.end() ) {
    127127                                return true;
    128                         }
    129                         else {
     128                        } else {
    130129                                assertf(false, "closed: %s", inst->name.c_str());
    131130                        }
  • src/InitTweak/FixInitNew.cpp

    r92355883 r2a301ff  
    2222#include "AST/SymbolTable.hpp"
    2323#include "AST/Type.hpp"
    24 #include "CodeGen/GenType.h"           // for genPrettyType
    25 #include "CodeGen/OperatorTable.h"
    26 #include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
     24#include "CodeGen/OperatorTable.h"     // for isConstructor, isCtorDtor, isD...
    2725#include "Common/SemanticError.h"      // for SemanticError
    2826#include "Common/ToString.hpp"         // for toCString
     
    3331#include "ResolvExpr/Resolver.h"       // for findVoidExpression
    3432#include "ResolvExpr/Unify.h"          // for typesCompatible
    35 #include "SymTab/Autogen.h"            // for genImplicitCall
    3633#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    37 #include "SymTab/Indexer.h"            // for Indexer
    38 #include "SymTab/Mangler.h"            // for Mangler
    39 #include "SynTree/LinkageSpec.h"       // for C, Spec, Cforall, isBuiltin
    40 #include "SynTree/Attribute.h"         // for Attribute
    41 #include "SynTree/Constant.h"          // for Constant
    42 #include "SynTree/Declaration.h"       // for ObjectDecl, FunctionDecl, Decl...
    43 #include "SynTree/Expression.h"        // for UniqueExpr, VariableExpr, Unty...
    44 #include "SynTree/Initializer.h"       // for ConstructorInit, SingleInit
    45 #include "SynTree/Label.h"             // for Label, operator<
    46 #include "SynTree/Mutator.h"           // for mutateAll, Mutator, maybeMutate
    47 #include "SynTree/Statement.h"         // for ExprStmt, CompoundStmt, Branch...
    48 #include "SynTree/Type.h"              // for Type, Type::StorageClasses
    49 #include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
    50 #include "SynTree/DeclReplacer.h"      // for DeclReplacer
    51 #include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    52 #include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    5334
    5435extern bool ctordtorp; // print all debug
     
    6142
    6243namespace InitTweak {
     44
    6345namespace {
    6446
    65         // Shallow copy the pointer list for return.
    66         std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) {
    67                 if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
    68                         return inst->base->params;
    69                 }
    70                 if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
    71                         return inst->base->params;
    72                 }
    73                 return {};
    74         }
    75 
    76         /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
    77         ast::FunctionDecl * genDefaultFunc(
    78                         const CodeLocation loc,
    79                         const std::string fname,
    80                         const ast::Type * paramType,
    81                         bool maybePolymorphic = true) {
    82                 std::vector<ast::ptr<ast::TypeDecl>> typeParams;
    83                 if ( maybePolymorphic ) typeParams = getGenericParams( paramType );
    84                 auto dstParam = new ast::ObjectDecl( loc,
    85                         "_dst",
    86                         new ast::ReferenceType( paramType ),
    87                         nullptr,
    88                         {},
    89                         ast::Linkage::Cforall
     47// Shallow copy the pointer list for return.
     48std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) {
     49        if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
     50                return inst->base->params;
     51        }
     52        if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
     53                return inst->base->params;
     54        }
     55        return {};
     56}
     57
     58/// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
     59ast::FunctionDecl * genDefaultFunc(
     60                const CodeLocation loc,
     61                const std::string fname,
     62                const ast::Type * paramType,
     63                bool maybePolymorphic = true) {
     64        std::vector<ast::ptr<ast::TypeDecl>> typeParams;
     65        if ( maybePolymorphic ) typeParams = getGenericParams( paramType );
     66        auto dstParam = new ast::ObjectDecl( loc,
     67                "_dst",
     68                new ast::ReferenceType( paramType ),
     69                nullptr,
     70                {},
     71                ast::Linkage::Cforall
     72        );
     73        return new ast::FunctionDecl( loc,
     74                fname,
     75                std::move(typeParams),
     76                {dstParam},
     77                {},
     78                new ast::CompoundStmt(loc),
     79                {},
     80                ast::Linkage::Cforall
     81        );
     82}
     83
     84struct SelfAssignChecker {
     85        void previsit( const ast::ApplicationExpr * appExpr );
     86};
     87
     88struct StmtExprResult {
     89        const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr );
     90};
     91
     92/// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
     93/// function calls need their parameters to be copy constructed
     94struct InsertImplicitCalls : public ast::WithShortCircuiting {
     95        const ast::Expr * postvisit( const ast::ApplicationExpr * appExpr );
     96
     97        // only handles each UniqueExpr once
     98        // if order of visit does not change, this should be safe
     99        void previsit (const ast::UniqueExpr *);
     100
     101        std::unordered_set<decltype(ast::UniqueExpr::id)> visitedIds;
     102};
     103
     104/// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
     105/// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
     106/// arguments and return value temporaries
     107struct ResolveCopyCtors final : public ast::WithGuards, public ast::WithStmtsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithVisitorRef<ResolveCopyCtors>, public ast::WithConstTranslationUnit {
     108        const ast::Expr * postvisit( const ast::ImplicitCopyCtorExpr * impCpCtorExpr );
     109        const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr );
     110        const ast::UniqueExpr * previsit( const ast::UniqueExpr * unqExpr );
     111
     112        /// handles distant mutations of environment manually.
     113        /// WithConstTypeSubstitution cannot remember where the environment is from
     114
     115        /// MUST be called at start of overload previsit
     116        void previsit( const ast::Expr * expr);
     117        /// MUST be called at return of overload postvisit
     118        const ast::Expr * postvisit(const ast::Expr * expr);
     119
     120        /// create and resolve ctor/dtor expression: fname(var, [cpArg])
     121        const ast::Expr * makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg = nullptr );
     122        /// true if type does not need to be copy constructed to ensure correctness
     123        bool skipCopyConstruct( const ast::Type * type );
     124        ast::ptr< ast::Expr > copyConstructArg( const ast::Expr * arg, const ast::ImplicitCopyCtorExpr * impCpCtorExpr, const ast::Type * formal );
     125        ast::Expr * destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg );
     126private:
     127        /// hack to implement WithTypeSubstitution while conforming to mutation safety.
     128        ast::TypeSubstitution * env         = nullptr;
     129        bool                    envModified = false;
     130};
     131
     132/// collects constructed object decls - used as a base class
     133struct ObjDeclCollector : public ast::WithGuards, public ast::WithShortCircuiting {
     134        // use ordered data structure to maintain ordering for set_difference and for consistent error messages
     135        typedef std::list< const ast::ObjectDecl * > ObjectSet;
     136        void previsit( const ast::CompoundStmt *compoundStmt );
     137        void previsit( const ast::DeclStmt *stmt );
     138
     139        // don't go into other functions
     140        void previsit( const ast::FunctionDecl * ) { visit_children = false; }
     141
     142protected:
     143        ObjectSet curVars;
     144};
     145
     146// debug
     147template<typename ObjectSet>
     148struct PrintSet {
     149        PrintSet( const ObjectSet & objs ) : objs( objs ) {}
     150        const ObjectSet & objs;
     151};
     152template<typename ObjectSet>
     153PrintSet<ObjectSet> printSet( const ObjectSet & objs ) { return PrintSet<ObjectSet>( objs ); }
     154template<typename ObjectSet>
     155std::ostream & operator<<( std::ostream & out, const PrintSet<ObjectSet> & set) {
     156        out << "{ ";
     157        for ( auto & obj : set.objs ) {
     158                out << obj->name << ", " ;
     159        } // for
     160        out << " }";
     161        return out;
     162}
     163
     164struct LabelFinder final : public ObjDeclCollector {
     165        typedef std::map< std::string, ObjectSet > LabelMap;
     166        // map of Label -> live variables at that label
     167        LabelMap vars;
     168
     169        typedef ObjDeclCollector Parent;
     170        using Parent::previsit;
     171        void previsit( const ast::Stmt * stmt );
     172
     173        void previsit( const ast::CompoundStmt *compoundStmt );
     174        void previsit( const ast::DeclStmt *stmt );
     175};
     176
     177/// insert destructor calls at the appropriate places.  must happen before CtorInit nodes are removed
     178/// (currently by FixInit)
     179struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> {
     180        typedef std::list< ObjectDecl * > OrderedDecls;
     181        typedef std::list< OrderedDecls > OrderedDeclsStack;
     182
     183        InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {}
     184
     185        typedef ObjDeclCollector Parent;
     186        using Parent::previsit;
     187
     188        void previsit( const ast::FunctionDecl * funcDecl );
     189
     190        void previsit( const ast::BranchStmt * stmt );
     191private:
     192        void handleGoto( const ast::BranchStmt * stmt );
     193
     194        ast::Pass<LabelFinder> & finder;
     195        LabelFinder::LabelMap & labelVars;
     196        OrderedDeclsStack reverseDeclOrder;
     197};
     198
     199/// expand each object declaration to use its constructor after it is declared.
     200struct FixInit : public ast::WithStmtsToAdd<> {
     201        static void fixInitializers( ast::TranslationUnit &translationUnit );
     202
     203        const ast::DeclWithType * postvisit( const ast::ObjectDecl *objDecl );
     204
     205        std::list< ast::ptr< ast::Decl > > staticDtorDecls;
     206};
     207
     208/// generate default/copy ctor and dtor calls for user-defined struct ctor/dtors
     209/// for any member that is missing a corresponding ctor/dtor call.
     210/// error if a member is used before constructed
     211struct GenStructMemberCalls final : public ast::WithGuards, public ast::WithShortCircuiting, public ast::WithSymbolTable, public ast::WithVisitorRef<GenStructMemberCalls>, public ast::WithConstTranslationUnit {
     212        void previsit( const ast::FunctionDecl * funcDecl );
     213        const ast::DeclWithType * postvisit( const ast::FunctionDecl * funcDecl );
     214
     215        void previsit( const ast::MemberExpr * memberExpr );
     216        void previsit( const ast::ApplicationExpr * appExpr );
     217
     218        /// Note: this post mutate used to be in a separate visitor. If this pass breaks, one place to examine is whether it is
     219        /// okay for this part of the recursion to occur alongside the rest.
     220        const ast::Expr * postvisit( const ast::UntypedExpr * expr );
     221
     222        SemanticErrorException errors;
     223private:
     224        template< typename... Params >
     225        void emit( CodeLocation, const Params &... params );
     226
     227        ast::FunctionDecl * function = nullptr;
     228        std::set< const ast::DeclWithType * > unhandled;
     229        std::map< const ast::DeclWithType *, CodeLocation > usedUninit;
     230        const ast::ObjectDecl * thisParam = nullptr;
     231        bool isCtor = false; // true if current function is a constructor
     232        const ast::StructDecl * structDecl = nullptr;
     233};
     234
     235/// expands ConstructorExpr nodes into comma expressions, using a temporary for the first argument
     236struct FixCtorExprs final : public ast::WithDeclsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithConstTranslationUnit {
     237        const ast::Expr * postvisit( const ast::ConstructorExpr * ctorExpr );
     238};
     239
     240/// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
     241struct SplitExpressions : public ast::WithShortCircuiting {
     242        ast::Stmt * postvisit( const ast::ExprStmt * stmt );
     243        void previsit( const ast::TupleAssignExpr * expr );
     244};
     245
     246/// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk
     247/// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration
     248const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) {
     249        const CodeLocation loc = input->location;
     250        // unwrap implicit statement wrapper
     251        // Statement * dtor = input;
     252        assert( input );
     253        // std::list< const ast::Expr * > matches;
     254        auto matches = collectCtorDtorCalls( input );
     255
     256        if ( dynamic_cast< const ast::ExprStmt * >( input ) ) {
     257                // only one destructor call in the expression
     258                if ( matches.size() == 1 ) {
     259                        auto func = getFunction( matches.front() );
     260                        assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
     261
     262                        // cleanup argument must be a function, not an object (including function pointer)
     263                        if ( auto dtorFunc = dynamic_cast< const ast::FunctionDecl * > ( func ) ) {
     264                                if ( dtorFunc->type->forall.empty() ) {
     265                                        // simple case where the destructor is a monomorphic function call - can simply
     266                                        // use that function as the cleanup function.
     267                                        return func;
     268                                }
     269                        }
     270                }
     271        }
     272
     273        // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
     274        // wraps the more complicated code.
     275        static UniqueName dtorNamer( "__cleanup_dtor" );
     276        std::string name = dtorNamer.newName();
     277        ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
     278        stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );
     279
     280        // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
     281        const ast::ObjectDecl * thisParam = getParamThis( dtorFunc );
     282        const ast::Expr * replacement = new ast::VariableExpr( loc, thisParam );
     283
     284        auto base = replacement->result->stripReferences();
     285        if ( dynamic_cast< const ast::ArrayType * >( base ) || dynamic_cast< const ast::TupleType * > ( base ) ) {
     286                // need to cast away reference for array types, since the destructor is generated without the reference type,
     287                // and for tuple types since tuple indexing does not work directly on a reference
     288                replacement = new ast::CastExpr( replacement, base );
     289        }
     290        auto dtor = ast::DeclReplacer::replace( input, ast::DeclReplacer::ExprMap{ std::make_pair( objDecl, replacement ) } );
     291        auto mutStmts = dtorFunc->stmts.get_and_mutate();
     292        mutStmts->push_back(strict_dynamic_cast<const ast::Stmt *>( dtor ));
     293        dtorFunc->stmts = mutStmts;
     294
     295        return dtorFunc;
     296}
     297
     298void FixInit::fixInitializers( ast::TranslationUnit & translationUnit ) {
     299        ast::Pass<FixInit> fixer;
     300
     301        // can't use mutateAll, because need to insert declarations at top-level
     302        // can't use DeclMutator, because sometimes need to insert IfStmt, etc.
     303        SemanticErrorException errors;
     304        for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) {
     305                try {
     306                        // maybeAccept( *i, fixer ); translationUnit should never contain null
     307                        *i = (*i)->accept(fixer);
     308                        translationUnit.decls.splice( i, fixer.core.staticDtorDecls );
     309                } catch( SemanticErrorException &e ) {
     310                        errors.append( e );
     311                } // try
     312        } // for
     313        if ( ! errors.isEmpty() ) {
     314                throw errors;
     315        } // if
     316}
     317
     318const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) {
     319        // we might loose the result expression here so add a pointer to trace back
     320        assert( stmtExpr->result );
     321        const ast::Type * result = stmtExpr->result;
     322        if ( ! result->isVoid() ) {
     323                auto mutExpr = mutate(stmtExpr);
     324                const ast::CompoundStmt * body = mutExpr->stmts;
     325                assert( ! body->kids.empty() );
     326                mutExpr->resultExpr = body->kids.back().strict_as<ast::ExprStmt>();
     327                return mutExpr;
     328        }
     329        return stmtExpr;
     330}
     331
     332ast::Stmt * SplitExpressions::postvisit( const ast::ExprStmt * stmt ) {
     333        // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
     334        // in the correct places
     335        ast::CompoundStmt * ret = new ast::CompoundStmt( stmt->location, { stmt } );
     336        return ret;
     337}
     338
     339void SplitExpressions::previsit( const ast::TupleAssignExpr * ) {
     340        // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions
     341        visit_children = false;
     342}
     343
     344// Relatively simple structural comparison for expressions, needed to determine
     345// if two expressions are "the same" (used to determine if self assignment occurs)
     346struct StructuralChecker {
     347        // Strip all casts and then dynamic_cast.
     348        template<typename T>
     349        static const T * cast( const ast::Expr * expr ) {
     350                // this might be too permissive. It's possible that only particular casts are relevant.
     351                while ( auto cast = dynamic_cast< const ast::CastExpr * >( expr ) ) {
     352                        expr = cast->arg;
     353                }
     354                return dynamic_cast< const T * >( expr );
     355        }
     356
     357        void previsit( const ast::Expr * ) {
     358                // anything else does not qualify
     359                result = false;
     360        }
     361
     362        // ignore casts
     363        void previsit( const ast::CastExpr * ) {}
     364
     365        void previsit( const ast::MemberExpr * memExpr ) {
     366                if ( auto otherMember = cast< ast::MemberExpr >( other ) ) {
     367                        if ( otherMember->member == memExpr->member ) {
     368                                other = otherMember->aggregate;
     369                                return;
     370                        }
     371                }
     372                result = false;
     373        }
     374
     375        void previsit( const ast::VariableExpr * varExpr ) {
     376                if ( auto otherVar = cast< ast::VariableExpr >( other ) ) {
     377                        if ( otherVar->var == varExpr->var ) {
     378                                return;
     379                        }
     380                }
     381                result = false;
     382        }
     383
     384        void previsit( const ast::AddressExpr * ) {
     385                if ( auto addrExpr = cast< ast::AddressExpr >( other ) ) {
     386                        other = addrExpr->arg;
     387                        return;
     388                }
     389                result = false;
     390        }
     391
     392        const ast::Expr * other;
     393        bool result = true;
     394        StructuralChecker( const ast::Expr * other ) : other(other) {}
     395};
     396
     397bool structurallySimilar( const ast::Expr * e1, const ast::Expr * e2 ) {
     398        return ast::Pass<StructuralChecker>::read( e1, e2 );
     399}
     400
     401void SelfAssignChecker::previsit( const ast::ApplicationExpr * appExpr ) {
     402        auto function = getFunction( appExpr );
     403        // Doesn't use isAssignment, because ?+=?, etc. should not count as self-assignment.
     404        if ( function->name == "?=?" && appExpr->args.size() == 2
     405                        // Check for structural similarity (same variable use, ignore casts, etc.
     406                        // (but does not look too deeply, anything looking like a function is off limits).
     407                        && structurallySimilar( appExpr->args.front(), appExpr->args.back() ) ) {
     408                SemanticWarning( appExpr->location, Warning::SelfAssignment, toCString( appExpr->args.front() ) );
     409        }
     410}
     411
     412const ast::Expr * InsertImplicitCalls::postvisit( const ast::ApplicationExpr * appExpr ) {
     413        if ( auto function = appExpr->func.as<ast::VariableExpr>() ) {
     414                if ( function->var->linkage.is_builtin ) {
     415                        // optimization: don't need to copy construct in order to call intrinsic functions
     416                        return appExpr;
     417                } else if ( auto funcDecl = function->var.as<ast::DeclWithType>() ) {
     418                        auto ftype = dynamic_cast< const ast::FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) );
     419                        assertf( ftype, "Function call without function type: %s", toString( funcDecl ).c_str() );
     420                        if ( CodeGen::isConstructor( funcDecl->name ) && ftype->params.size() == 2 ) {
     421                                auto t1 = getPointerBase( ftype->params.front() );
     422                                auto t2 = ftype->params.back();
     423                                assert( t1 );
     424
     425                                if ( ResolvExpr::typesCompatible( t1, t2 ) ) {
     426                                        // optimization: don't need to copy construct in order to call a copy constructor
     427                                        return appExpr;
     428                                } // if
     429                        } else if ( CodeGen::isDestructor( funcDecl->name ) ) {
     430                                // correctness: never copy construct arguments to a destructor
     431                                return appExpr;
     432                        } // if
     433                } // if
     434        } // if
     435        CP_CTOR_PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; )
     436
     437        // wrap each function call so that it is easy to identify nodes that have to be copy constructed
     438        ast::ptr<ast::TypeSubstitution> tmp = appExpr->env;
     439        auto mutExpr = mutate(appExpr);
     440        mutExpr->env = nullptr;
     441
     442        auto expr = new ast::ImplicitCopyCtorExpr( appExpr->location, mutExpr );
     443        // Move the type substitution to the new top-level. The substitution
     444        // is needed to obtain the type of temporary variables so that copy
     445        // constructor calls can be resolved.
     446        expr->env = tmp;
     447        return expr;
     448}
     449
     450void ResolveCopyCtors::previsit(const ast::Expr * expr) {
     451        if ( nullptr == expr->env ) {
     452                return;
     453        }
     454        GuardValue( env ) = expr->env->clone();
     455        GuardValue( envModified ) = false;
     456}
     457
     458const ast::Expr * ResolveCopyCtors::postvisit(const ast::Expr * expr) {
     459        // No local environment, skip.
     460        if ( nullptr == expr->env ) {
     461                return expr;
     462        // Environment was modified, mutate and replace.
     463        } else if ( envModified ) {
     464                auto mutExpr = mutate(expr);
     465                mutExpr->env = env;
     466                return mutExpr;
     467        // Environment was not mutated, delete the shallow copy before guard.
     468        } else {
     469                delete env;
     470                return expr;
     471        }
     472}
     473
     474bool ResolveCopyCtors::skipCopyConstruct( const ast::Type * type ) { return ! isConstructable( type ); }
     475
     476const ast::Expr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg ) {
     477        assert( var );
     478        assert( var->isManaged() );
     479        assert( !cpArg || cpArg->isManaged() );
     480        // arrays are not copy constructed, so this should always be an ExprStmt
     481        ast::ptr< ast::Stmt > stmt = genCtorDtor(var->location, fname, var, cpArg );
     482        assertf( stmt, "ResolveCopyCtors: genCtorDtor returned nullptr: %s / %s / %s", fname.c_str(), toString( var ).c_str(), toString( cpArg ).c_str() );
     483        auto exprStmt = stmt.strict_as<ast::ImplicitCtorDtorStmt>()->callStmt.strict_as<ast::ExprStmt>();
     484        ast::ptr<ast::Expr> untyped = exprStmt->expr; // take ownership of expr
     485
     486        // resolve copy constructor
     487        // should only be one alternative for copy ctor and dtor expressions, since all arguments are fixed
     488        // (VariableExpr and already resolved expression)
     489        CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; )
     490        ast::ptr<ast::Expr> resolved = ResolvExpr::findVoidExpression(untyped, { symtab, transUnit().global } );
     491        assert( resolved );
     492        if ( resolved->env ) {
     493                // Extract useful information and discard new environments. Keeping them causes problems in PolyMutator passes.
     494                env->add( *resolved->env );
     495                envModified = true;
     496                auto mut = mutate(resolved.get());
     497                assertf(mut == resolved.get(), "newly resolved expression must be unique");
     498                mut->env = nullptr;
     499        } // if
     500        if ( auto assign = resolved.as<ast::TupleAssignExpr>() ) {
     501                // fix newly generated StmtExpr
     502                previsit( assign->stmtExpr );
     503        }
     504        return resolved.release();
     505}
     506
     507ast::ptr<ast::Expr> ResolveCopyCtors::copyConstructArg(
     508        const ast::Expr * arg, const ast::ImplicitCopyCtorExpr * impCpCtorExpr, const ast::Type * formal )
     509{
     510        static UniqueName tempNamer("_tmp_cp");
     511        const CodeLocation loc = impCpCtorExpr->location;
     512        // CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; )
     513        assert( arg->result );
     514        ast::ptr<ast::Type> result = arg->result;
     515        if ( skipCopyConstruct( result ) ) return arg; // skip certain non-copyable types
     516
     517        // type may involve type variables, so apply type substitution to get temporary variable's actual type,
     518        // since result type may not be substituted (e.g., if the type does not appear in the parameter list)
     519        // Use applyFree so that types bound in function pointers are not substituted, e.g. in forall(dtype T) void (*)(T).
     520
     521        // xxx - this originally mutates arg->result in place. is it correct?
     522        assert( env );
     523        result = env->applyFree( result.get() ).node;
     524        auto mutResult = result.get_and_mutate();
     525        mutResult->set_const(false);
     526
     527        auto mutArg = mutate(arg);
     528        mutArg->result = mutResult;
     529
     530        ast::ptr<ast::Expr> guard = mutArg;
     531
     532        ast::ptr<ast::ObjectDecl> tmp = new ast::ObjectDecl(loc, "__tmp", mutResult, nullptr );
     533
     534        // create and resolve copy constructor
     535        CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )
     536        auto cpCtor = makeCtorDtor( "?{}", tmp, mutArg );
     537
     538        if ( auto appExpr = dynamic_cast< const ast::ApplicationExpr * >( cpCtor ) ) {
     539                // if the chosen constructor is intrinsic, the copy is unnecessary, so
     540                // don't create the temporary and don't call the copy constructor
     541                auto function = appExpr->func.strict_as<ast::VariableExpr>();
     542                if ( function->var->linkage == ast::Linkage::Intrinsic ) {
     543                        // arguments that need to be boxed need a temporary regardless of whether the copy constructor is intrinsic,
     544                        // so that the object isn't changed inside of the polymorphic function
     545                        if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) {
     546                                // xxx - should arg->result be mutated? see comment above.
     547                                return guard;
     548                        }
     549                }
     550        }
     551
     552        // set a unique name for the temporary once it's certain the call is necessary
     553        auto mut = tmp.get_and_mutate();
     554        assertf (mut == tmp, "newly created ObjectDecl must be unique");
     555        mut->name = tempNamer.newName();
     556
     557        // replace argument to function call with temporary
     558        stmtsToAddBefore.push_back( new ast::DeclStmt(loc, tmp ) );
     559        arg = cpCtor;
     560        return destructRet( tmp, arg );
     561
     562        // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
     563}
     564
     565ast::Expr * ResolveCopyCtors::destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg ) {
     566        auto global = transUnit().global;
     567        // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
     568        // check for existing cleanup attribute before adding another(?)
     569        // need to add __Destructor for _tmp_cp variables as well
     570
     571        assertf( global.dtorStruct, "Destructor generation requires __Destructor definition." );
     572        assertf( global.dtorStruct->members.size() == 2, "__Destructor definition does not have expected fields." );
     573        assertf( global.dtorDestroy, "Destructor generation requires __destroy_Destructor." );
     574
     575        const CodeLocation loc = ret->location;
     576
     577        // generate a __Destructor for ret that calls the destructor
     578        auto res = makeCtorDtor( "^?{}", ret );
     579        auto dtor = mutate(res);
     580
     581        // if the chosen destructor is intrinsic, elide the generated dtor handler
     582        if ( arg && isIntrinsicCallExpr( dtor ) ) {
     583                return new ast::CommaExpr(loc, arg, new ast::VariableExpr(loc, ret ) );
     584        }
     585
     586        if ( ! dtor->env ) dtor->env = maybeClone( env );
     587        auto dtorFunc = getDtorFunc( ret, new ast::ExprStmt(loc, dtor ), stmtsToAddBefore );
     588
     589        auto dtorStructType = new ast::StructInstType( global.dtorStruct );
     590
     591        // what does this do???
     592        dtorStructType->params.push_back( new ast::TypeExpr(loc, new ast::VoidType() ) );
     593
     594        // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     595        auto dtorFtype = new ast::FunctionType();
     596        dtorFtype->params.push_back( new ast::PointerType(new ast::VoidType( ) ) );
     597        auto dtorType = new ast::PointerType( dtorFtype );
     598
     599        static UniqueName namer( "_ret_dtor" );
     600        auto retDtor = new ast::ObjectDecl(loc, namer.newName(), dtorStructType, new ast::ListInit(loc, { new ast::SingleInit(loc, ast::ConstantExpr::null(loc) ), new ast::SingleInit(loc, new ast::CastExpr( new ast::VariableExpr(loc, dtorFunc ), dtorType ) ) } ) );
     601        retDtor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, global.dtorDestroy ) } ) );
     602        stmtsToAddBefore.push_back( new ast::DeclStmt(loc, retDtor ) );
     603
     604        if ( arg ) {
     605                auto member = new ast::MemberExpr(loc, global.dtorStruct->members.front().strict_as<ast::DeclWithType>(), new ast::VariableExpr(loc, retDtor ) );
     606                auto object = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, ret ) ), new ast::PointerType(new ast::VoidType() ) );
     607                ast::Expr * assign = createBitwiseAssignment( member, object );
     608                return new ast::CommaExpr(loc, new ast::CommaExpr(loc, arg, assign ), new ast::VariableExpr(loc, ret ) );
     609        }
     610        return nullptr;
     611        // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
     612}
     613
     614const ast::Expr * ResolveCopyCtors::postvisit( const ast::ImplicitCopyCtorExpr *impCpCtorExpr ) {
     615        CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
     616
     617        ast::ApplicationExpr * appExpr = mutate(impCpCtorExpr->callExpr.get());
     618        const ast::ObjectDecl * returnDecl = nullptr;
     619        const CodeLocation loc = appExpr->location;
     620
     621        // take each argument and attempt to copy construct it.
     622        auto ftype = GenPoly::getFunctionType( appExpr->func->result );
     623        assert( ftype );
     624        auto & params = ftype->params;
     625        auto iter = params.begin();
     626        for ( auto & arg : appExpr->args ) {
     627                const ast::Type * formal = nullptr;
     628                if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
     629                        // DeclarationWithType * param = *iter++;
     630                        formal = *iter++;
     631                }
     632
     633                arg = copyConstructArg( arg, impCpCtorExpr, formal );
     634        } // for
     635
     636        // each return value from the call needs to be connected with an ObjectDecl at the call site, which is
     637        // initialized with the return value and is destructed later
     638        // xxx - handle named return values?
     639        const ast::Type * result = appExpr->result;
     640        if ( ! result->isVoid() ) {
     641                static UniqueName retNamer("_tmp_cp_ret");
     642                auto subResult = env->apply( result ).node;
     643                auto ret = new ast::ObjectDecl(loc, retNamer.newName(), subResult, nullptr );
     644                auto mutType = mutate(ret->type.get());
     645                mutType->set_const( false );
     646                ret->type = mutType;
     647                returnDecl = ret;
     648                stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );
     649                CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
     650        } // for
     651        CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
     652        // ------------------------------------------------------
     653
     654        CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
     655
     656        // detach fields from wrapper node so that it can be deleted without deleting too much
     657
     658        // xxx - actual env might be somewhere else, need to keep invariant
     659
     660        // deletion of wrapper should be handled by pass template now
     661
     662        // impCpCtorExpr->callExpr = nullptr;
     663        assert (appExpr->env == nullptr);
     664        appExpr->env = impCpCtorExpr->env;
     665        // std::swap( impCpCtorExpr->env, appExpr->env );
     666        // assert( impCpCtorExpr->env == nullptr );
     667        // delete impCpCtorExpr;
     668
     669        if ( returnDecl ) {
     670                ast::Expr * assign = createBitwiseAssignment( new ast::VariableExpr(loc, returnDecl ), appExpr );
     671                if ( ! dynamic_cast< const ast::ReferenceType * >( result ) ) {
     672                        // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
     673                        assign = destructRet( returnDecl, assign );
     674                        assert(assign);
     675                } else {
     676                        assign = new ast::CommaExpr(loc, assign, new ast::VariableExpr(loc, returnDecl ) );
     677                }
     678                // move env from appExpr to retExpr
     679                // std::swap( assign->env, appExpr->env );
     680                assign->env = appExpr->env;
     681                // actual env is handled by common routine that replaces WithTypeSubstitution
     682                return postvisit((const ast::Expr *)assign);
     683        } else {
     684                return postvisit((const ast::Expr *)appExpr);
     685        } // if
     686}
     687
     688const ast::StmtExpr * ResolveCopyCtors::previsit( const ast::StmtExpr * _stmtExpr ) {
     689        // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
     690        // since temporaries can be shared across sub-expressions, e.g.
     691        //   [A, A] f();       // decl
     692        //   g([A] x, [A] y);  // decl
     693        //   g(f());           // call
     694        // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
     695        // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added
     696        // to the outer context, rather than inside of the statement expression.
     697
     698        // call the common routine that replaces WithTypeSubstitution
     699        previsit((const ast::Expr *) _stmtExpr);
     700
     701        visit_children = false;
     702        const CodeLocation loc = _stmtExpr->location;
     703
     704        assert( env );
     705
     706        symtab.enterScope();
     707        // visit all statements
     708        auto stmtExpr = mutate(_stmtExpr);
     709        auto mutStmts = mutate(stmtExpr->stmts.get());
     710
     711        auto & stmts = mutStmts->kids;
     712        for ( auto & stmt : stmts ) {
     713                stmt = stmt->accept( *visitor );
     714        } // for
     715        stmtExpr->stmts = mutStmts;
     716        symtab.leaveScope();
     717
     718        assert( stmtExpr->result );
     719        // const ast::Type * result = stmtExpr->result;
     720        if ( ! stmtExpr->result->isVoid() ) {
     721                static UniqueName retNamer("_tmp_stmtexpr_ret");
     722
     723                // result = result->clone();
     724                auto result = env->apply( stmtExpr->result.get() ).node;
     725                if ( ! InitTweak::isConstructable( result ) ) {
     726                        // delete result;
     727                        return stmtExpr;
     728                }
     729                auto mutResult = result.get_and_mutate();
     730                mutResult->set_const(false);
     731
     732                // create variable that will hold the result of the stmt expr
     733                auto ret = new ast::ObjectDecl(loc, retNamer.newName(), mutResult, nullptr );
     734                stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );
     735
     736                assertf(
     737                        stmtExpr->resultExpr,
     738                        "Statement-Expression should have a resulting expression at %s:%d",
     739                        stmtExpr->location.filename.c_str(),
     740                        stmtExpr->location.first_line
    90741                );
    91                 return new ast::FunctionDecl( loc,
    92                         fname,
    93                         std::move(typeParams),
    94                         {dstParam},
    95                         {},
    96                         new ast::CompoundStmt(loc),
    97                         {},
    98                         ast::Linkage::Cforall
    99                 );
    100         }
    101 
    102         struct SelfAssignChecker {
    103                 void previsit( const ast::ApplicationExpr * appExpr );
    104         };
    105 
    106         struct StmtExprResult {
    107                 const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr );
    108         };
    109 
    110         /// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
    111         /// function calls need their parameters to be copy constructed
    112         struct InsertImplicitCalls : public ast::WithShortCircuiting {
    113                 const ast::Expr * postvisit( const ast::ApplicationExpr * appExpr );
    114 
    115                 // only handles each UniqueExpr once
    116                 // if order of visit does not change, this should be safe
    117                 void previsit (const ast::UniqueExpr *);
    118 
    119                 std::unordered_set<decltype(ast::UniqueExpr::id)> visitedIds;
    120         };
    121 
    122         /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
    123         /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
    124         /// arguments and return value temporaries
    125         struct ResolveCopyCtors final : public ast::WithGuards, public ast::WithStmtsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithVisitorRef<ResolveCopyCtors>, public ast::WithConstTranslationUnit {
    126                 const ast::Expr * postvisit( const ast::ImplicitCopyCtorExpr * impCpCtorExpr );
    127                 const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr );
    128                 const ast::UniqueExpr * previsit( const ast::UniqueExpr * unqExpr );
    129 
    130                 /// handles distant mutations of environment manually.
    131                 /// WithConstTypeSubstitution cannot remember where the environment is from
    132 
    133                 /// MUST be called at start of overload previsit
    134                 void previsit( const ast::Expr * expr);
    135                 /// MUST be called at return of overload postvisit
    136                 const ast::Expr * postvisit(const ast::Expr * expr);
    137 
    138                 /// create and resolve ctor/dtor expression: fname(var, [cpArg])
    139                 const ast::Expr * makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg = nullptr );
    140                 /// true if type does not need to be copy constructed to ensure correctness
    141                 bool skipCopyConstruct( const ast::Type * type );
    142                 ast::ptr< ast::Expr > copyConstructArg( const ast::Expr * arg, const ast::ImplicitCopyCtorExpr * impCpCtorExpr, const ast::Type * formal );
    143                 ast::Expr * destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg );
    144         private:
    145                 /// hack to implement WithTypeSubstitution while conforming to mutation safety.
    146                 ast::TypeSubstitution * env         = nullptr;
    147                 bool                    envModified = false;
    148         };
    149 
    150         /// collects constructed object decls - used as a base class
    151         struct ObjDeclCollector : public ast::WithGuards, public ast::WithShortCircuiting {
    152                 // use ordered data structure to maintain ordering for set_difference and for consistent error messages
    153                 typedef std::list< const ast::ObjectDecl * > ObjectSet;
    154                 void previsit( const ast::CompoundStmt *compoundStmt );
    155                 void previsit( const ast::DeclStmt *stmt );
    156 
    157                 // don't go into other functions
    158                 void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    159 
    160         protected:
    161                 ObjectSet curVars;
    162         };
    163 
    164         // debug
    165         template<typename ObjectSet>
    166         struct PrintSet {
    167                 PrintSet( const ObjectSet & objs ) : objs( objs ) {}
    168                 const ObjectSet & objs;
    169         };
    170         template<typename ObjectSet>
    171         PrintSet<ObjectSet> printSet( const ObjectSet & objs ) { return PrintSet<ObjectSet>( objs ); }
    172         template<typename ObjectSet>
    173         std::ostream & operator<<( std::ostream & out, const PrintSet<ObjectSet> & set) {
    174                 out << "{ ";
    175                 for ( auto & obj : set.objs ) {
    176                         out << obj->name << ", " ;
    177                 } // for
    178                 out << " }";
    179                 return out;
    180         }
    181 
    182         struct LabelFinder final : public ObjDeclCollector {
    183                 typedef std::map< std::string, ObjectSet > LabelMap;
    184                 // map of Label -> live variables at that label
    185                 LabelMap vars;
    186 
    187                 typedef ObjDeclCollector Parent;
    188                 using Parent::previsit;
    189                 void previsit( const ast::Stmt * stmt );
    190 
    191                 void previsit( const ast::CompoundStmt *compoundStmt );
    192                 void previsit( const ast::DeclStmt *stmt );
    193         };
    194 
    195         /// insert destructor calls at the appropriate places.  must happen before CtorInit nodes are removed
    196         /// (currently by FixInit)
    197         struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> {
    198                 typedef std::list< ObjectDecl * > OrderedDecls;
    199                 typedef std::list< OrderedDecls > OrderedDeclsStack;
    200 
    201                 InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {}
    202 
    203                 typedef ObjDeclCollector Parent;
    204                 using Parent::previsit;
    205 
    206                 void previsit( const ast::FunctionDecl * funcDecl );
    207 
    208                 void previsit( const ast::BranchStmt * stmt );
    209         private:
    210                 void handleGoto( const ast::BranchStmt * stmt );
    211 
    212                 ast::Pass<LabelFinder> & finder;
    213                 LabelFinder::LabelMap & labelVars;
    214                 OrderedDeclsStack reverseDeclOrder;
    215         };
    216 
    217         /// expand each object declaration to use its constructor after it is declared.
    218         struct FixInit : public ast::WithStmtsToAdd<> {
    219                 static void fixInitializers( ast::TranslationUnit &translationUnit );
    220 
    221                 const ast::DeclWithType * postvisit( const ast::ObjectDecl *objDecl );
    222 
    223                 std::list< ast::ptr< ast::Decl > > staticDtorDecls;
    224         };
    225 
    226         /// generate default/copy ctor and dtor calls for user-defined struct ctor/dtors
    227         /// for any member that is missing a corresponding ctor/dtor call.
    228         /// error if a member is used before constructed
    229         struct GenStructMemberCalls final : public ast::WithGuards, public ast::WithShortCircuiting, public ast::WithSymbolTable, public ast::WithVisitorRef<GenStructMemberCalls>, public ast::WithConstTranslationUnit {
    230                 void previsit( const ast::FunctionDecl * funcDecl );
    231                 const ast::DeclWithType * postvisit( const ast::FunctionDecl * funcDecl );
    232 
    233                 void previsit( const ast::MemberExpr * memberExpr );
    234                 void previsit( const ast::ApplicationExpr * appExpr );
    235 
    236                 /// Note: this post mutate used to be in a separate visitor. If this pass breaks, one place to examine is whether it is
    237                 /// okay for this part of the recursion to occur alongside the rest.
    238                 const ast::Expr * postvisit( const ast::UntypedExpr * expr );
    239 
    240                 SemanticErrorException errors;
    241         private:
    242                 template< typename... Params >
    243                 void emit( CodeLocation, const Params &... params );
    244 
    245                 ast::FunctionDecl * function = nullptr;
    246                 std::set< const ast::DeclWithType * > unhandled;
    247                 std::map< const ast::DeclWithType *, CodeLocation > usedUninit;
    248                 const ast::ObjectDecl * thisParam = nullptr;
    249                 bool isCtor = false; // true if current function is a constructor
    250                 const ast::StructDecl * structDecl = nullptr;
    251         };
    252 
    253         /// expands ConstructorExpr nodes into comma expressions, using a temporary for the first argument
    254         struct FixCtorExprs final : public ast::WithDeclsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithConstTranslationUnit {
    255                 const ast::Expr * postvisit( const ast::ConstructorExpr * ctorExpr );
    256         };
    257 
    258         /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
    259         struct SplitExpressions : public ast::WithShortCircuiting {
    260                 ast::Stmt * postvisit( const ast::ExprStmt * stmt );
    261                 void previsit( const ast::TupleAssignExpr * expr );
    262         };
     742
     743                const ast::ExprStmt * last = stmtExpr->resultExpr;
     744                // xxx - if this is non-unique, need to copy while making resultExpr ref
     745                assertf(last->unique(), "attempt to modify weakly shared statement");
     746                auto mutLast = mutate(last);
     747                // above assertion means in-place mutation is OK
     748                try {
     749                        mutLast->expr = makeCtorDtor( "?{}", ret, mutLast->expr );
     750                } catch(...) {
     751                        std::cerr << "*CFA internal error: ";
     752                        std::cerr << "can't resolve implicit constructor";
     753                        std::cerr << " at " << stmtExpr->location.filename;
     754                        std::cerr << ":" << stmtExpr->location.first_line << std::endl;
     755
     756                        abort();
     757                }
     758
     759                // add destructors after current statement
     760                stmtsToAddAfter.push_back( new ast::ExprStmt(loc, makeCtorDtor( "^?{}", ret ) ) );
     761
     762                // must have a non-empty body, otherwise it wouldn't have a result
     763                assert( ! stmts.empty() );
     764
     765                // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
     766                stmts.push_back( new ast::ExprStmt(loc, new ast::VariableExpr(loc, ret ) ) );
     767        } // if
     768
     769        assert( stmtExpr->returnDecls.empty() );
     770        assert( stmtExpr->dtors.empty() );
     771
     772        return stmtExpr;
     773}
     774
     775// to prevent warnings ('_unq0' may be used uninitialized in this function),
     776// insert an appropriate zero initializer for UniqueExpr temporaries.
     777ast::Init * makeInit( const ast::Type * t, CodeLocation const & loc ) {
     778        if ( auto inst = dynamic_cast< const ast::StructInstType * >( t ) ) {
     779                // initizer for empty struct must be empty
     780                if ( inst->base->members.empty() ) {
     781                        return new ast::ListInit( loc, {} );
     782                }
     783        } else if ( auto inst = dynamic_cast< const ast::UnionInstType * >( t ) ) {
     784                // initizer for empty union must be empty
     785                if ( inst->base->members.empty() ) {
     786                        return new ast::ListInit( loc, {} );
     787                }
     788        }
     789
     790        return new ast::ListInit( loc, {
     791                new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) )
     792        } );
     793}
     794
     795const ast::UniqueExpr * ResolveCopyCtors::previsit( const ast::UniqueExpr * unqExpr ) {
     796        visit_children = false;
     797        // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     798        static std::unordered_map< int, const ast::UniqueExpr * > unqMap;
     799        auto mutExpr = mutate(unqExpr);
     800        if ( ! unqMap.count( unqExpr->id ) ) {
     801                // resolve expr and find its
     802
     803                auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>();
     804                // PassVisitor<ResolveCopyCtors> fixer;
     805
     806                mutExpr->expr = mutExpr->expr->accept( *visitor );
     807                // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
     808                assert( unqExpr->result );
     809                if ( impCpCtorExpr ) {
     810                        auto comma = unqExpr->expr.strict_as<ast::CommaExpr>();
     811                        auto var = comma->arg2.strict_as<ast::VariableExpr>();
     812                        // note the variable used as the result from the call
     813                        mutExpr->var = var;
     814                } else {
     815                        // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
     816                        mutExpr->object = new ast::ObjectDecl( mutExpr->location, toString("_unq", mutExpr->id), mutExpr->result, makeInit( mutExpr->result, mutExpr->location ) );
     817                        mutExpr->var = new ast::VariableExpr( mutExpr->location, mutExpr->object );
     818                }
     819
     820                unqMap[mutExpr->id] = mutExpr;
     821        } else {
     822                // take data from other UniqueExpr to ensure consistency
     823                // delete unqExpr->get_expr();
     824                mutExpr->expr = unqMap[mutExpr->id]->expr;
     825                // delete unqExpr->result;
     826                mutExpr->result = mutExpr->expr->result;
     827        }
     828        return mutExpr;
     829}
     830
     831const ast::DeclWithType * FixInit::postvisit( const ast::ObjectDecl *_objDecl ) {
     832        const CodeLocation loc = _objDecl->location;
     833
     834        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postvisit)
     835        if ( ast::ptr<ast::ConstructorInit> ctorInit = _objDecl->init.as<ast::ConstructorInit>() ) {
     836                auto objDecl = mutate(_objDecl);
     837
     838                // could this be non-unique?
     839                if (objDecl != _objDecl) {
     840                        std::cerr << "FixInit: non-unique object decl " << objDecl->location << objDecl->name << std::endl;
     841                }
     842                // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     843                assert( ! ctorInit->ctor || ! ctorInit->init );
     844                if ( const ast::Stmt * ctor = ctorInit->ctor ) {
     845                        if ( objDecl->storage.is_static ) {
     846                                addDataSectionAttribute(objDecl);
     847                                // originally wanted to take advantage of gcc nested functions, but
     848                                // we get memory errors with this approach. To remedy this, the static
     849                                // variable is hoisted when the destructor needs to be called.
     850                                //
     851                                // generate:
     852                                // static T __objName_static_varN;
     853                                // void __objName_dtor_atexitN() {
     854                                //   __dtor__...;
     855                                // }
     856                                // int f(...) {
     857                                //   ...
     858                                //   static bool __objName_uninitialized = true;
     859                                //   if (__objName_uninitialized) {
     860                                //     __ctor(__objName);
     861                                //     __objName_uninitialized = false;
     862                                //     atexit(__objName_dtor_atexitN);
     863                                //   }
     864                                //   ...
     865                                // }
     866
     867                                static UniqueName dtorCallerNamer( "_dtor_atexit" );
     868
     869                                // static bool __objName_uninitialized = true
     870                                auto boolType = new ast::BasicType( ast::BasicType::Kind::Bool );
     871                                auto boolInitExpr = new ast::SingleInit(loc, ast::ConstantExpr::from_int(loc, 1 ) );
     872                                auto isUninitializedVar = new ast::ObjectDecl(loc, objDecl->mangleName + "_uninitialized", boolType, boolInitExpr, ast::Storage::Static, ast::Linkage::Cforall);
     873                                isUninitializedVar->fixUniqueId();
     874
     875                                // __objName_uninitialized = false;
     876                                auto setTrue = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ) );
     877                                setTrue->args.push_back( new ast::VariableExpr(loc, isUninitializedVar ) );
     878                                setTrue->args.push_back( ast::ConstantExpr::from_int(loc, 0 ) );
     879
     880                                // generate body of if
     881                                auto initStmts = new ast::CompoundStmt(loc);
     882                                auto & body = initStmts->kids;
     883                                body.push_back( ctor );
     884                                body.push_back( new ast::ExprStmt(loc, setTrue ) );
     885
     886                                // put it all together
     887                                auto ifStmt = new ast::IfStmt(loc, new ast::VariableExpr(loc, isUninitializedVar ), initStmts, 0 );
     888                                stmtsToAddAfter.push_back( new ast::DeclStmt(loc, isUninitializedVar ) );
     889                                stmtsToAddAfter.push_back( ifStmt );
     890
     891                                const ast::Stmt * dtor = ctorInit->dtor;
     892
     893                                // these should be automatically managed once reassigned
     894                                // objDecl->set_init( nullptr );
     895                                // ctorInit->set_ctor( nullptr );
     896                                // ctorInit->set_dtor( nullptr );
     897                                if ( dtor ) {
     898                                        // if the object has a non-trivial destructor, have to
     899                                        // hoist it and the object into the global space and
     900                                        // call the destructor function with atexit.
     901
     902                                        // Statement * dtorStmt = dtor->clone();
     903
     904                                        // void __objName_dtor_atexitN(...) {...}
     905                                        ast::FunctionDecl * dtorCaller = new ast::FunctionDecl(loc, objDecl->mangleName + dtorCallerNamer.newName(), {}, {}, {}, new ast::CompoundStmt(loc, {dtor}), ast::Storage::Static, ast::Linkage::C );
     906                                        dtorCaller->fixUniqueId();
     907                                        // dtorCaller->stmts->push_back( dtor );
     908
     909                                        // atexit(dtor_atexit);
     910                                        auto callAtexit = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "atexit" ) );
     911                                        callAtexit->args.push_back( new ast::VariableExpr(loc, dtorCaller ) );
     912
     913                                        body.push_back( new ast::ExprStmt(loc, callAtexit ) );
     914
     915                                        // hoist variable and dtor caller decls to list of decls that will be added into global scope
     916                                        staticDtorDecls.push_back( objDecl );
     917                                        staticDtorDecls.push_back( dtorCaller );
     918
     919                                        // need to rename object uniquely since it now appears
     920                                        // at global scope and there could be multiple function-scoped
     921                                        // static variables with the same name in different functions.
     922                                        // Note: it isn't sufficient to modify only the mangleName, because
     923                                        // then subsequent Indexer passes can choke on seeing the object's name
     924                                        // if another object has the same name and type. An unfortunate side-effect
     925                                        // of renaming the object is that subsequent NameExprs may fail to resolve,
     926                                        // but there shouldn't be any remaining past this point.
     927                                        static UniqueName staticNamer( "_static_var" );
     928                                        objDecl->name = objDecl->name + staticNamer.newName();
     929                                        objDecl->mangleName = Mangle::mangle( objDecl );
     930                                        objDecl->init = nullptr;
     931
     932                                        // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
     933                                        // create a new object which is never used
     934                                        static UniqueName dummyNamer( "_dummy" );
     935                                        auto dummy = new ast::ObjectDecl(loc, dummyNamer.newName(), new ast::PointerType(new ast::VoidType()), nullptr, ast::Storage::Static, ast::Linkage::Cforall, 0, { new ast::Attribute("unused") } );
     936                                        // delete ctorInit;
     937                                        return dummy;
     938                                } else {
     939                                        objDecl->init = nullptr;
     940                                        return objDecl;
     941                                }
     942                        } else {
     943                                auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * > ( ctor );
     944                                auto ctorStmt = implicit->callStmt.as<ast::ExprStmt>();
     945                                const ast::ApplicationExpr * ctorCall = nullptr;
     946                                if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->args.size() == 2 ) {
     947                                        // clean up intrinsic copy constructor calls by making them into SingleInits
     948                                        const ast::Expr * ctorArg = ctorCall->args.back();
     949                                        // ctorCall should be gone afterwards
     950                                        auto mutArg = mutate(ctorArg);
     951                                        mutArg->env = ctorCall->env;
     952                                        // std::swap( ctorArg->env, ctorCall->env );
     953                                        objDecl->init = new ast::SingleInit(loc, mutArg );
     954
     955                                        // ctorCall->args.pop_back();
     956                                } else {
     957                                        stmtsToAddAfter.push_back( ctor );
     958                                        objDecl->init = nullptr;
     959                                        // ctorInit->ctor = nullptr;
     960                                }
     961
     962                                const ast::Stmt * dtor = ctorInit->dtor;
     963                                if ( dtor ) {
     964                                        auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * >( dtor );
     965                                        const ast::Stmt * dtorStmt = implicit->callStmt;
     966
     967                                        // don't need to call intrinsic dtor, because it does nothing, but
     968                                        // non-intrinsic dtors must be called
     969                                        if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
     970                                                // set dtor location to the object's location for error messages
     971                                                auto dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
     972                                                objDecl->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, dtorFunc ) } ) );
     973                                                // ctorInit->dtor = nullptr;
     974                                        } // if
     975                                }
     976                        } // if
     977                } else if ( const ast::Init * init = ctorInit->init ) {
     978                        objDecl->init = init;
     979                        // ctorInit->init = nullptr;
     980                } else {
     981                        // no constructor and no initializer, which is okay
     982                        objDecl->init = nullptr;
     983                } // if
     984                // delete ctorInit;
     985                return objDecl;
     986        } // if
     987        return _objDecl;
     988}
     989
     990void ObjDeclCollector::previsit( const ast::CompoundStmt * ) {
     991        GuardValue( curVars );
     992}
     993
     994void ObjDeclCollector::previsit( const ast::DeclStmt * stmt ) {
     995        // keep track of all variables currently in scope
     996        if ( auto objDecl = stmt->decl.as<ast::ObjectDecl>() ) {
     997                curVars.push_back( objDecl );
     998        } // if
     999}
     1000
     1001void LabelFinder::previsit( const ast::Stmt * stmt ) {
     1002        // for each label, remember the variables in scope at that label.
     1003        for ( auto l : stmt->labels ) {
     1004                vars[l] = curVars;
     1005        } // for
     1006}
     1007
     1008void LabelFinder::previsit( const ast::CompoundStmt * stmt ) {
     1009        previsit( (const ast::Stmt *) stmt );
     1010        Parent::previsit( stmt );
     1011}
     1012
     1013void LabelFinder::previsit( const ast::DeclStmt * stmt ) {
     1014        previsit( (const ast::Stmt *)stmt );
     1015        Parent::previsit( stmt );
     1016}
     1017
     1018void InsertDtors::previsit( const ast::FunctionDecl * funcDecl ) {
     1019        // each function needs to have its own set of labels
     1020        GuardValue( labelVars );
     1021        labelVars.clear();
     1022        // LabelFinder does not recurse into FunctionDecl, so need to visit
     1023        // its children manually.
     1024        if (funcDecl->type) funcDecl->type->accept(finder);
     1025        // maybeAccept( funcDecl->type, finder );
     1026        if (funcDecl->stmts) funcDecl->stmts->accept(finder) ;
     1027
     1028        // all labels for this function have been collected, insert destructors as appropriate via implicit recursion.
     1029}
     1030
     1031// Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
     1032// BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     1033// at the target location but not at the BranchStmt then those objects would be uninitialized so notify the user
     1034// of the error.  See C++ Reference 6.6 Jump Statements for details.
     1035void InsertDtors::handleGoto( const ast::BranchStmt * stmt ) {
     1036        // can't do anything for computed goto
     1037        if ( stmt->computedTarget ) return;
     1038
     1039        assertf( stmt->target.name != "", "BranchStmt missing a label: %s", toString( stmt ).c_str() );
     1040        // S_L = lvars = set of objects in scope at label definition
     1041        // S_G = curVars = set of objects in scope at goto statement
     1042        ObjectSet & lvars = labelVars[ stmt->target ];
     1043
     1044        DTOR_PRINT(
     1045                std::cerr << "at goto label: " << stmt->target.name << std::endl;
     1046                std::cerr << "S_G = " << printSet( curVars ) << std::endl;
     1047                std::cerr << "S_L = " << printSet( lvars ) << std::endl;
     1048        )
     1049
     1050
     1051        // std::set_difference requires that the inputs be sorted.
     1052        lvars.sort();
     1053        curVars.sort();
     1054
     1055        ObjectSet diff;
     1056        // S_L-S_G results in set of objects whose construction is skipped - it's an error if this set is non-empty
     1057        std::set_difference( lvars.begin(), lvars.end(), curVars.begin(), curVars.end(), std::inserter( diff, diff.begin() ) );
     1058        DTOR_PRINT(
     1059                std::cerr << "S_L-S_G = " << printSet( diff ) << std::endl;
     1060        )
     1061        if ( ! diff.empty() ) {
     1062                SemanticError( stmt, std::string("jump to label '") + stmt->target.name + "' crosses initialization of " + (*diff.begin())->name + " " );
     1063        } // if
     1064}
     1065
     1066void InsertDtors::previsit( const ast::BranchStmt * stmt ) {
     1067        switch( stmt->kind ) {
     1068        case ast::BranchStmt::Continue:
     1069        case ast::BranchStmt::Break:
     1070                // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
     1071                // always be empty), but it serves as a small sanity check.
     1072        case ast::BranchStmt::Goto:
     1073                handleGoto( stmt );
     1074                break;
     1075        default:
     1076                assert( false );
     1077        } // switch
     1078}
     1079
     1080bool checkWarnings( const ast::FunctionDecl * funcDecl ) {
     1081        // only check for warnings if the current function is a user-defined
     1082        // constructor or destructor
     1083        if ( ! funcDecl ) return false;
     1084        if ( ! funcDecl->stmts ) return false;
     1085        return CodeGen::isCtorDtor( funcDecl->name ) && ! funcDecl->linkage.is_overrideable;
     1086}
     1087
     1088void GenStructMemberCalls::previsit( const ast::FunctionDecl * funcDecl ) {
     1089        GuardValue( function );
     1090        GuardValue( unhandled );
     1091        GuardValue( usedUninit );
     1092        GuardValue( thisParam );
     1093        GuardValue( isCtor );
     1094        GuardValue( structDecl );
     1095        errors = SemanticErrorException();  // clear previous errors
     1096
     1097        // need to start with fresh sets
     1098        unhandled.clear();
     1099        usedUninit.clear();
     1100
     1101        function = mutate(funcDecl);
     1102        // could this be non-unique?
     1103        if (function != funcDecl) {
     1104                std::cerr << "GenStructMemberCalls: non-unique FunctionDecl " << funcDecl->location << funcDecl->name << std::endl;
     1105        }
     1106
     1107        isCtor = CodeGen::isConstructor( function->name );
     1108        if ( checkWarnings( function ) ) {
     1109                // const ast::FunctionType * type = function->type;
     1110                // assert( ! type->params.empty() );
     1111                thisParam = function->params.front().strict_as<ast::ObjectDecl>();
     1112                auto thisType = getPointerBase( thisParam->get_type() );
     1113                auto structType = dynamic_cast< const ast::StructInstType * >( thisType );
     1114                if ( structType ) {
     1115                        structDecl = structType->base;
     1116                        for ( auto & member : structDecl->members ) {
     1117                                if ( auto field = member.as<ast::ObjectDecl>() ) {
     1118                                        // record all of the struct type's members that need to be constructed or
     1119                                        // destructed by the end of the function
     1120                                        unhandled.insert( field );
     1121                                }
     1122                        }
     1123                }
     1124        }
     1125}
     1126
     1127const ast::DeclWithType * GenStructMemberCalls::postvisit( const ast::FunctionDecl * funcDecl ) {
     1128        // remove the unhandled objects from usedUninit, because a call is inserted
     1129        // to handle them - only objects that are later constructed are used uninitialized.
     1130        std::map< const ast::DeclWithType *, CodeLocation > diff;
     1131        // need the comparator since usedUninit and unhandled have different types
     1132        struct comp_t {
     1133                typedef decltype(usedUninit)::value_type usedUninit_t;
     1134                typedef decltype(unhandled)::value_type unhandled_t;
     1135                bool operator()(usedUninit_t x, unhandled_t y) { return x.first < y; }
     1136                bool operator()(unhandled_t x, usedUninit_t y) { return x < y.first; }
     1137        } comp;
     1138        std::set_difference( usedUninit.begin(), usedUninit.end(), unhandled.begin(), unhandled.end(), std::inserter( diff, diff.begin() ), comp );
     1139        for ( auto p : diff ) {
     1140                auto member = p.first;
     1141                auto loc = p.second;
     1142                // xxx - make error message better by also tracking the location that the object is constructed at?
     1143                emit( loc, "in ", function->name, ", field ", member->name, " used before being constructed" );
     1144        }
     1145
     1146        const CodeLocation loc = funcDecl->location;
     1147
     1148        if ( ! unhandled.empty() ) {
     1149                auto mutStmts = function->stmts.get_and_mutate();
     1150                // need to explicitly re-add function parameters to the indexer in order to resolve copy constructors
     1151                auto guard = makeFuncGuard( [this]() { symtab.enterScope(); }, [this]() { symtab.leaveScope(); } );
     1152                symtab.addFunction( function );
     1153                auto global = transUnit().global;
     1154
     1155                // need to iterate through members in reverse in order for
     1156                // ctor/dtor statements to come out in the right order
     1157                for ( auto & member : reverseIterate( structDecl->members ) ) {
     1158                        auto field = member.as<ast::ObjectDecl>();
     1159                        // skip non-DWT members
     1160                        if ( ! field ) continue;
     1161                        // skip non-constructable members
     1162                        if ( ! tryConstruct( field ) ) continue;
     1163                        // skip handled members
     1164                        if ( ! unhandled.count( field ) ) continue;
     1165
     1166                        // insert and resolve default/copy constructor call for each field that's unhandled
     1167                        // std::list< const ast::Stmt * > stmt;
     1168                        ast::Expr * arg2 = nullptr;
     1169                        if ( function->name == "?{}" && isCopyFunction( function ) ) {
     1170                                // if copy ctor, need to pass second-param-of-this-function.field
     1171                                // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
     1172                                assert( function->params.size() == 2 );
     1173                                arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) );
     1174                        }
     1175                        InitExpander_new srcParam( arg2 );
     1176                        // cast away reference type and construct field.
     1177                        ast::Expr * thisExpr = new ast::CastExpr(funcDecl->location, new ast::VariableExpr(funcDecl->location, thisParam ), thisParam->get_type()->stripReferences());
     1178                        ast::Expr * memberDest = new ast::MemberExpr(funcDecl->location, field, thisExpr );
     1179                        ast::ptr<ast::Stmt> callStmt = SymTab::genImplicitCall( srcParam, memberDest, loc, function->name, field, static_cast<SymTab::LoopDirection>(isCtor) );
     1180
     1181                        if ( callStmt ) {
     1182                                // auto & callStmt = stmt.front();
     1183
     1184                                try {
     1185                                        callStmt = callStmt->accept( *visitor );
     1186                                        if ( isCtor ) {
     1187                                                mutStmts->push_front( callStmt );
     1188                                        } else { // TODO: don't generate destructor function/object for intrinsic calls
     1189                                                // destructor statements should be added at the end
     1190                                                // function->get_statements()->push_back( callStmt );
     1191
     1192                                                // Optimization: do not need to call intrinsic destructors on members
     1193                                                if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue;
     1194
     1195                                                // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };
     1196                                                std::list< ast::ptr<ast::Stmt> > stmtsToAdd;
     1197
     1198                                                static UniqueName memberDtorNamer = { "__memberDtor" };
     1199                                                assertf( global.dtorStruct, "builtin __Destructor not found." );
     1200                                                assertf( global.dtorDestroy, "builtin __destroy_Destructor not found." );
     1201
     1202                                                ast::Expr * thisExpr = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, thisParam ) ), new ast::PointerType( new ast::VoidType(), ast::CV::Qualifiers() ) );
     1203                                                ast::Expr * dtorExpr = new ast::VariableExpr(loc, getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
     1204
     1205                                                // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     1206                                                auto dtorFtype = new ast::FunctionType();
     1207                                                dtorFtype->params.emplace_back( new ast::PointerType( new ast::VoidType() ) );
     1208                                                auto dtorType = new ast::PointerType( dtorFtype );
     1209
     1210                                                auto destructor = new ast::ObjectDecl(loc, memberDtorNamer.newName(), new ast::StructInstType( global.dtorStruct ), new ast::ListInit(loc, { new ast::SingleInit(loc, thisExpr ), new ast::SingleInit(loc, new ast::CastExpr( dtorExpr, dtorType ) ) } ) );
     1211                                                destructor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr( loc, global.dtorDestroy ) } ) );
     1212                                                mutStmts->push_front( new ast::DeclStmt(loc, destructor ) );
     1213                                                mutStmts->kids.splice( mutStmts->kids.begin(), stmtsToAdd );
     1214                                        }
     1215                                } catch ( SemanticErrorException & error ) {
     1216                                        emit( funcDecl->location, "in ", function->name , ", field ", field->name, " not explicitly ", isCtor ? "constructed" : "destructed",  " and no ", isCtor ? "default constructor" : "destructor", " found" );
     1217                                }
     1218                        }
     1219                }
     1220                function->stmts = mutStmts;
     1221        }
     1222        if (! errors.isEmpty()) {
     1223                throw errors;
     1224        }
     1225        // return funcDecl;
     1226        return function;
     1227}
     1228
     1229/// true if expr is effectively just the 'this' parameter
     1230bool isThisExpression( const ast::Expr * expr, const ast::DeclWithType * thisParam ) {
     1231        // TODO: there are more complicated ways to pass 'this' to a constructor, e.g. &*, *&, etc.
     1232        if ( auto varExpr = dynamic_cast< const ast::VariableExpr * >( expr ) ) {
     1233                return varExpr->var == thisParam;
     1234        } else if ( auto castExpr = dynamic_cast< const ast::CastExpr * > ( expr ) ) {
     1235                return isThisExpression( castExpr->arg, thisParam );
     1236        }
     1237        return false;
     1238}
     1239
     1240/// returns a MemberExpr if expr is effectively just member access on the 'this' parameter, else nullptr
     1241const ast::MemberExpr * isThisMemberExpr( const ast::Expr * expr, const ast::DeclWithType * thisParam ) {
     1242        if ( auto memberExpr = dynamic_cast< const ast::MemberExpr * >( expr ) ) {
     1243                if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
     1244                        return memberExpr;
     1245                }
     1246        } else if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {
     1247                return isThisMemberExpr( castExpr->arg, thisParam );
     1248        }
     1249        return nullptr;
     1250}
     1251
     1252void GenStructMemberCalls::previsit( const ast::ApplicationExpr * appExpr ) {
     1253        if ( ! checkWarnings( function ) ) {
     1254                visit_children = false;
     1255                return;
     1256        }
     1257
     1258        std::string fname = getFunctionName( appExpr );
     1259        if ( fname == function->name ) {
     1260                // call to same kind of function
     1261                const ast::Expr * firstParam = appExpr->args.front();
     1262
     1263                if ( isThisExpression( firstParam, thisParam ) ) {
     1264                        // if calling another constructor on thisParam, assume that function handles
     1265                        // all members - if it doesn't a warning will appear in that function.
     1266                        unhandled.clear();
     1267                } else if ( auto memberExpr = isThisMemberExpr( firstParam, thisParam ) ) {
     1268                        // if first parameter is a member expression on the this parameter,
     1269                        // then remove the member from unhandled set.
     1270                        if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
     1271                                unhandled.erase( memberExpr->member );
     1272                        }
     1273                }
     1274        }
     1275}
     1276
     1277void GenStructMemberCalls::previsit( const ast::MemberExpr * memberExpr ) {
     1278        if ( ! checkWarnings( function ) || ! isCtor ) {
     1279                visit_children = false;
     1280                return;
     1281        }
     1282
     1283        if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
     1284                if ( unhandled.count( memberExpr->member ) ) {
     1285                        // emit a warning because a member was used before it was constructed
     1286                        usedUninit.insert( { memberExpr->member, memberExpr->location } );
     1287                }
     1288        }
     1289}
     1290
     1291template< typename... Params >
     1292void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
     1293        SemanticErrorException err( loc, toString( params... ) );
     1294        errors.append( err );
     1295}
     1296
     1297const ast::Expr * GenStructMemberCalls::postvisit( const ast::UntypedExpr * untypedExpr ) {
     1298        // xxx - functions returning ast::ptr seems wrong...
     1299        auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
     1300        return res.release();
     1301}
     1302
     1303void InsertImplicitCalls::previsit(const ast::UniqueExpr * unqExpr) {
     1304        if (visitedIds.count(unqExpr->id)) visit_children = false;
     1305        else visitedIds.insert(unqExpr->id);
     1306}
     1307
     1308const ast::Expr * FixCtorExprs::postvisit( const ast::ConstructorExpr * ctorExpr ) {
     1309        const CodeLocation loc = ctorExpr->location;
     1310        static UniqueName tempNamer( "_tmp_ctor_expr" );
     1311        // xxx - is the size check necessary?
     1312        assert( ctorExpr->result && ctorExpr->result->size() == 1 );
     1313
     1314        // xxx - this can be TupleAssignExpr now. Need to properly handle this case.
     1315        // take possession of expr and env
     1316        ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>();
     1317        ast::ptr<ast::TypeSubstitution> env = ctorExpr->env;
     1318        // ctorExpr->set_callExpr( nullptr );
     1319        // ctorExpr->set_env( nullptr );
     1320
     1321        // xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary.
     1322        auto tmp = new ast::ObjectDecl(loc, tempNamer.newName(), callExpr->args.front()->result );
     1323        declsToAddBefore.push_back( tmp );
     1324
     1325        // build assignment and replace constructor's first argument with new temporary
     1326        auto mutCallExpr = callExpr.get_and_mutate();
     1327        const ast::Expr * firstArg = callExpr->args.front();
     1328        ast::Expr * assign = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ), { new ast::AddressExpr(loc, new ast::VariableExpr(loc, tmp ) ), new ast::AddressExpr( firstArg ) } );
     1329        firstArg = new ast::VariableExpr(loc, tmp );
     1330        mutCallExpr->args.front() = firstArg;
     1331
     1332        // resolve assignment and dispose of new env
     1333        auto resolved = ResolvExpr::findVoidExpression( assign, { symtab, transUnit().global } );
     1334        auto mut = resolved.get_and_mutate();
     1335        assertf(resolved.get() == mut, "newly resolved expression must be unique");
     1336        mut->env = nullptr;
     1337
     1338        // for constructor expr:
     1339        //   T x;
     1340        //   x{};
     1341        // results in:
     1342        //   T x;
     1343        //   T & tmp;
     1344        //   &tmp = &x, ?{}(tmp), tmp
     1345        ast::CommaExpr * commaExpr = new ast::CommaExpr(loc, resolved, new ast::CommaExpr(loc, mutCallExpr, new ast::VariableExpr(loc, tmp ) ) );
     1346        commaExpr->env = env;
     1347        return commaExpr;
     1348}
     1349
    2631350} // namespace
    2641351
     
    2931380}
    2941381
    295 namespace {
    296         /// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk
    297         /// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration
    298         const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) {
    299                 const CodeLocation loc = input->location;
    300                 // unwrap implicit statement wrapper
    301                 // Statement * dtor = input;
    302                 assert( input );
    303                 // std::list< const ast::Expr * > matches;
    304                 auto matches = collectCtorDtorCalls( input );
    305 
    306                 if ( dynamic_cast< const ast::ExprStmt * >( input ) ) {
    307                         // only one destructor call in the expression
    308                         if ( matches.size() == 1 ) {
    309                                 auto func = getFunction( matches.front() );
    310                                 assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
    311 
    312                                 // cleanup argument must be a function, not an object (including function pointer)
    313                                 if ( auto dtorFunc = dynamic_cast< const ast::FunctionDecl * > ( func ) ) {
    314                                         if ( dtorFunc->type->forall.empty() ) {
    315                                                 // simple case where the destructor is a monomorphic function call - can simply
    316                                                 // use that function as the cleanup function.
    317                                                 return func;
    318                                         }
    319                                 }
    320                         }
    321                 }
    322 
    323                 // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
    324                 // wraps the more complicated code.
    325                 static UniqueName dtorNamer( "__cleanup_dtor" );
    326                 std::string name = dtorNamer.newName();
    327                 ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
    328                 stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );
    329 
    330                 // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
    331                 const ast::ObjectDecl * thisParam = getParamThis( dtorFunc );
    332                 const ast::Expr * replacement = new ast::VariableExpr( loc, thisParam );
    333 
    334                 auto base = replacement->result->stripReferences();
    335                 if ( dynamic_cast< const ast::ArrayType * >( base ) || dynamic_cast< const ast::TupleType * > ( base ) ) {
    336                         // need to cast away reference for array types, since the destructor is generated without the reference type,
    337                         // and for tuple types since tuple indexing does not work directly on a reference
    338                         replacement = new ast::CastExpr( replacement, base );
    339                 }
    340                 auto dtor = ast::DeclReplacer::replace( input, ast::DeclReplacer::ExprMap{ std::make_pair( objDecl, replacement ) } );
    341                 auto mutStmts = dtorFunc->stmts.get_and_mutate();
    342                 mutStmts->push_back(strict_dynamic_cast<const ast::Stmt *>( dtor ));
    343                 dtorFunc->stmts = mutStmts;
    344 
    345                 return dtorFunc;
    346         }
    347 
    348         void FixInit::fixInitializers( ast::TranslationUnit & translationUnit ) {
    349                 ast::Pass<FixInit> fixer;
    350 
    351                 // can't use mutateAll, because need to insert declarations at top-level
    352                 // can't use DeclMutator, because sometimes need to insert IfStmt, etc.
    353                 SemanticErrorException errors;
    354                 for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) {
    355                         try {
    356                                 // maybeAccept( *i, fixer ); translationUnit should never contain null
    357                                 *i = (*i)->accept(fixer);
    358                                 translationUnit.decls.splice( i, fixer.core.staticDtorDecls );
    359                         } catch( SemanticErrorException &e ) {
    360                                 errors.append( e );
    361                         } // try
    362                 } // for
    363                 if ( ! errors.isEmpty() ) {
    364                         throw errors;
    365                 } // if
    366         }
    367 
    368         const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) {
    369                 // we might loose the result expression here so add a pointer to trace back
    370                 assert( stmtExpr->result );
    371                 const ast::Type * result = stmtExpr->result;
    372                 if ( ! result->isVoid() ) {
    373                         auto mutExpr = mutate(stmtExpr);
    374                         const ast::CompoundStmt * body = mutExpr->stmts;
    375                         assert( ! body->kids.empty() );
    376                         mutExpr->resultExpr = body->kids.back().strict_as<ast::ExprStmt>();
    377                         return mutExpr;
    378                 }
    379                 return stmtExpr;
    380         }
    381 
    382         ast::Stmt * SplitExpressions::postvisit( const ast::ExprStmt * stmt ) {
    383                 // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
    384                 // in the correct places
    385                 ast::CompoundStmt * ret = new ast::CompoundStmt( stmt->location, { stmt } );
    386                 return ret;
    387         }
    388 
    389         void SplitExpressions::previsit( const ast::TupleAssignExpr * ) {
    390                 // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions
    391                 visit_children = false;
    392         }
    393 
    394         // Relatively simple structural comparison for expressions, needed to determine
    395         // if two expressions are "the same" (used to determine if self assignment occurs)
    396         struct StructuralChecker {
    397                 // Strip all casts and then dynamic_cast.
    398                 template<typename T>
    399                 static const T * cast( const ast::Expr * expr ) {
    400                         // this might be too permissive. It's possible that only particular casts are relevant.
    401                         while ( auto cast = dynamic_cast< const ast::CastExpr * >( expr ) ) {
    402                                 expr = cast->arg;
    403                         }
    404                         return dynamic_cast< const T * >( expr );
    405                 }
    406 
    407                 void previsit( const ast::Expr * ) {
    408                         // anything else does not qualify
    409                         result = false;
    410                 }
    411 
    412                 // ignore casts
    413                 void previsit( const ast::CastExpr * ) {}
    414 
    415                 void previsit( const ast::MemberExpr * memExpr ) {
    416                         if ( auto otherMember = cast< ast::MemberExpr >( other ) ) {
    417                                 if ( otherMember->member == memExpr->member ) {
    418                                         other = otherMember->aggregate;
    419                                         return;
    420                                 }
    421                         }
    422                         result = false;
    423                 }
    424 
    425                 void previsit( const ast::VariableExpr * varExpr ) {
    426                         if ( auto otherVar = cast< ast::VariableExpr >( other ) ) {
    427                                 if ( otherVar->var == varExpr->var ) {
    428                                         return;
    429                                 }
    430                         }
    431                         result = false;
    432                 }
    433 
    434                 void previsit( const ast::AddressExpr * ) {
    435                         if ( auto addrExpr = cast< ast::AddressExpr >( other ) ) {
    436                                 other = addrExpr->arg;
    437                                 return;
    438                         }
    439                         result = false;
    440                 }
    441 
    442                 const ast::Expr * other;
    443                 bool result = true;
    444                 StructuralChecker( const ast::Expr * other ) : other(other) {}
    445         };
    446 
    447         bool structurallySimilar( const ast::Expr * e1, const ast::Expr * e2 ) {
    448                 return ast::Pass<StructuralChecker>::read( e1, e2 );
    449         }
    450 
    451         void SelfAssignChecker::previsit( const ast::ApplicationExpr * appExpr ) {
    452                 auto function = getFunction( appExpr );
    453                 // Doesn't use isAssignment, because ?+=?, etc. should not count as self-assignment.
    454                 if ( function->name == "?=?" && appExpr->args.size() == 2
    455                                 // Check for structural similarity (same variable use, ignore casts, etc.
    456                                 // (but does not look too deeply, anything looking like a function is off limits).
    457                                 && structurallySimilar( appExpr->args.front(), appExpr->args.back() ) ) {
    458                         SemanticWarning( appExpr->location, Warning::SelfAssignment, toCString( appExpr->args.front() ) );
    459                 }
    460         }
    461 
    462         const ast::Expr * InsertImplicitCalls::postvisit( const ast::ApplicationExpr * appExpr ) {
    463                 if ( auto function = appExpr->func.as<ast::VariableExpr>() ) {
    464                         if ( function->var->linkage.is_builtin ) {
    465                                 // optimization: don't need to copy construct in order to call intrinsic functions
    466                                 return appExpr;
    467                         } else if ( auto funcDecl = function->var.as<ast::DeclWithType>() ) {
    468                                 auto ftype = dynamic_cast< const ast::FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) );
    469                                 assertf( ftype, "Function call without function type: %s", toString( funcDecl ).c_str() );
    470                                 if ( CodeGen::isConstructor( funcDecl->name ) && ftype->params.size() == 2 ) {
    471                                         auto t1 = getPointerBase( ftype->params.front() );
    472                                         auto t2 = ftype->params.back();
    473                                         assert( t1 );
    474 
    475                                         if ( ResolvExpr::typesCompatible( t1, t2 ) ) {
    476                                                 // optimization: don't need to copy construct in order to call a copy constructor
    477                                                 return appExpr;
    478                                         } // if
    479                                 } else if ( CodeGen::isDestructor( funcDecl->name ) ) {
    480                                         // correctness: never copy construct arguments to a destructor
    481                                         return appExpr;
    482                                 } // if
    483                         } // if
    484                 } // if
    485                 CP_CTOR_PRINT( std::cerr << "InsertImplicitCalls: adding a wrapper " << appExpr << std::endl; )
    486 
    487                 // wrap each function call so that it is easy to identify nodes that have to be copy constructed
    488                 ast::ptr<ast::TypeSubstitution> tmp = appExpr->env;
    489                 auto mutExpr = mutate(appExpr);
    490                 mutExpr->env = nullptr;
    491 
    492                 auto expr = new ast::ImplicitCopyCtorExpr( appExpr->location, mutExpr );
    493                 // Move the type substitution to the new top-level. The substitution
    494                 // is needed to obtain the type of temporary variables so that copy
    495                 // constructor calls can be resolved.
    496                 expr->env = tmp;
    497                 return expr;
    498         }
    499 
    500         void ResolveCopyCtors::previsit(const ast::Expr * expr) {
    501                 if ( nullptr == expr->env ) {
    502                         return;
    503                 }
    504                 GuardValue( env ) = expr->env->clone();
    505                 GuardValue( envModified ) = false;
    506         }
    507 
    508         const ast::Expr * ResolveCopyCtors::postvisit(const ast::Expr * expr) {
    509                 // No local environment, skip.
    510                 if ( nullptr == expr->env ) {
    511                         return expr;
    512                 // Environment was modified, mutate and replace.
    513                 } else if ( envModified ) {
    514                         auto mutExpr = mutate(expr);
    515                         mutExpr->env = env;
    516                         return mutExpr;
    517                 // Environment was not mutated, delete the shallow copy before guard.
    518                 } else {
    519                         delete env;
    520                         return expr;
    521                 }
    522         }
    523 
    524         bool ResolveCopyCtors::skipCopyConstruct( const ast::Type * type ) { return ! isConstructable( type ); }
    525 
    526         const ast::Expr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg ) {
    527                 assert( var );
    528                 assert( var->isManaged() );
    529                 assert( !cpArg || cpArg->isManaged() );
    530                 // arrays are not copy constructed, so this should always be an ExprStmt
    531                 ast::ptr< ast::Stmt > stmt = genCtorDtor(var->location, fname, var, cpArg );
    532                 assertf( stmt, "ResolveCopyCtors: genCtorDtor returned nullptr: %s / %s / %s", fname.c_str(), toString( var ).c_str(), toString( cpArg ).c_str() );
    533                 auto exprStmt = stmt.strict_as<ast::ImplicitCtorDtorStmt>()->callStmt.strict_as<ast::ExprStmt>();
    534                 ast::ptr<ast::Expr> untyped = exprStmt->expr; // take ownership of expr
    535 
    536                 // resolve copy constructor
    537                 // should only be one alternative for copy ctor and dtor expressions, since all arguments are fixed
    538                 // (VariableExpr and already resolved expression)
    539                 CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; )
    540                 ast::ptr<ast::Expr> resolved = ResolvExpr::findVoidExpression(untyped, { symtab, transUnit().global } );
    541                 assert( resolved );
    542                 if ( resolved->env ) {
    543                         // Extract useful information and discard new environments. Keeping them causes problems in PolyMutator passes.
    544                         env->add( *resolved->env );
    545                         envModified = true;
    546                         auto mut = mutate(resolved.get());
    547                         assertf(mut == resolved.get(), "newly resolved expression must be unique");
    548                         mut->env = nullptr;
    549                 } // if
    550                 if ( auto assign = resolved.as<ast::TupleAssignExpr>() ) {
    551                         // fix newly generated StmtExpr
    552                         previsit( assign->stmtExpr );
    553                 }
    554                 return resolved.release();
    555         }
    556 
    557         ast::ptr<ast::Expr> ResolveCopyCtors::copyConstructArg(
    558                 const ast::Expr * arg, const ast::ImplicitCopyCtorExpr * impCpCtorExpr, const ast::Type * formal )
    559         {
    560                 static UniqueName tempNamer("_tmp_cp");
    561                 const CodeLocation loc = impCpCtorExpr->location;
    562                 // CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; )
    563                 assert( arg->result );
    564                 ast::ptr<ast::Type> result = arg->result;
    565                 if ( skipCopyConstruct( result ) ) return arg; // skip certain non-copyable types
    566 
    567                 // type may involve type variables, so apply type substitution to get temporary variable's actual type,
    568                 // since result type may not be substituted (e.g., if the type does not appear in the parameter list)
    569                 // Use applyFree so that types bound in function pointers are not substituted, e.g. in forall(dtype T) void (*)(T).
    570 
    571                 // xxx - this originally mutates arg->result in place. is it correct?
    572                 assert( env );
    573                 result = env->applyFree( result.get() ).node;
    574                 auto mutResult = result.get_and_mutate();
    575                 mutResult->set_const(false);
    576 
    577                 auto mutArg = mutate(arg);
    578                 mutArg->result = mutResult;
    579 
    580                 ast::ptr<ast::Expr> guard = mutArg;
    581 
    582                 ast::ptr<ast::ObjectDecl> tmp = new ast::ObjectDecl(loc, "__tmp", mutResult, nullptr );
    583 
    584                 // create and resolve copy constructor
    585                 CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )
    586                 auto cpCtor = makeCtorDtor( "?{}", tmp, mutArg );
    587 
    588                 if ( auto appExpr = dynamic_cast< const ast::ApplicationExpr * >( cpCtor ) ) {
    589                         // if the chosen constructor is intrinsic, the copy is unnecessary, so
    590                         // don't create the temporary and don't call the copy constructor
    591                         auto function = appExpr->func.strict_as<ast::VariableExpr>();
    592                         if ( function->var->linkage == ast::Linkage::Intrinsic ) {
    593                                 // arguments that need to be boxed need a temporary regardless of whether the copy constructor is intrinsic,
    594                                 // so that the object isn't changed inside of the polymorphic function
    595                                 if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) {
    596                                         // xxx - should arg->result be mutated? see comment above.
    597                                         return guard;
    598                                 }
    599                         }
    600                 }
    601 
    602                 // set a unique name for the temporary once it's certain the call is necessary
    603                 auto mut = tmp.get_and_mutate();
    604                 assertf (mut == tmp, "newly created ObjectDecl must be unique");
    605                 mut->name = tempNamer.newName();
    606 
    607                 // replace argument to function call with temporary
    608                 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, tmp ) );
    609                 arg = cpCtor;
    610                 return destructRet( tmp, arg );
    611 
    612                 // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
    613         }
    614 
    615         ast::Expr * ResolveCopyCtors::destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg ) {
    616                 auto global = transUnit().global;
    617                 // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
    618                 // check for existing cleanup attribute before adding another(?)
    619                 // need to add __Destructor for _tmp_cp variables as well
    620 
    621                 assertf( global.dtorStruct, "Destructor generation requires __Destructor definition." );
    622                 assertf( global.dtorStruct->members.size() == 2, "__Destructor definition does not have expected fields." );
    623                 assertf( global.dtorDestroy, "Destructor generation requires __destroy_Destructor." );
    624 
    625                 const CodeLocation loc = ret->location;
    626 
    627                 // generate a __Destructor for ret that calls the destructor
    628                 auto res = makeCtorDtor( "^?{}", ret );
    629                 auto dtor = mutate(res);
    630 
    631                 // if the chosen destructor is intrinsic, elide the generated dtor handler
    632                 if ( arg && isIntrinsicCallExpr( dtor ) ) {
    633                         return new ast::CommaExpr(loc, arg, new ast::VariableExpr(loc, ret ) );
    634                 }
    635 
    636                 if ( ! dtor->env ) dtor->env = maybeClone( env );
    637                 auto dtorFunc = getDtorFunc( ret, new ast::ExprStmt(loc, dtor ), stmtsToAddBefore );
    638 
    639                 auto dtorStructType = new ast::StructInstType( global.dtorStruct );
    640 
    641                 // what does this do???
    642                 dtorStructType->params.push_back( new ast::TypeExpr(loc, new ast::VoidType() ) );
    643 
    644                 // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
    645                 auto dtorFtype = new ast::FunctionType();
    646                 dtorFtype->params.push_back( new ast::PointerType(new ast::VoidType( ) ) );
    647                 auto dtorType = new ast::PointerType( dtorFtype );
    648 
    649                 static UniqueName namer( "_ret_dtor" );
    650                 auto retDtor = new ast::ObjectDecl(loc, namer.newName(), dtorStructType, new ast::ListInit(loc, { new ast::SingleInit(loc, ast::ConstantExpr::null(loc) ), new ast::SingleInit(loc, new ast::CastExpr( new ast::VariableExpr(loc, dtorFunc ), dtorType ) ) } ) );
    651                 retDtor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, global.dtorDestroy ) } ) );
    652                 stmtsToAddBefore.push_back( new ast::DeclStmt(loc, retDtor ) );
    653 
    654                 if ( arg ) {
    655                         auto member = new ast::MemberExpr(loc, global.dtorStruct->members.front().strict_as<ast::DeclWithType>(), new ast::VariableExpr(loc, retDtor ) );
    656                         auto object = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, ret ) ), new ast::PointerType(new ast::VoidType() ) );
    657                         ast::Expr * assign = createBitwiseAssignment( member, object );
    658                         return new ast::CommaExpr(loc, new ast::CommaExpr(loc, arg, assign ), new ast::VariableExpr(loc, ret ) );
    659                 }
    660                 return nullptr;
    661                 // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    662         }
    663 
    664         const ast::Expr * ResolveCopyCtors::postvisit( const ast::ImplicitCopyCtorExpr *impCpCtorExpr ) {
    665                 CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
    666 
    667                 ast::ApplicationExpr * appExpr = mutate(impCpCtorExpr->callExpr.get());
    668                 const ast::ObjectDecl * returnDecl = nullptr;
    669                 const CodeLocation loc = appExpr->location;
    670 
    671                 // take each argument and attempt to copy construct it.
    672                 auto ftype = GenPoly::getFunctionType( appExpr->func->result );
    673                 assert( ftype );
    674                 auto & params = ftype->params;
    675                 auto iter = params.begin();
    676                 for ( auto & arg : appExpr->args ) {
    677                         const ast::Type * formal = nullptr;
    678                         if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
    679                                 // DeclarationWithType * param = *iter++;
    680                                 formal = *iter++;
    681                         }
    682 
    683                         arg = copyConstructArg( arg, impCpCtorExpr, formal );
    684                 } // for
    685 
    686                 // each return value from the call needs to be connected with an ObjectDecl at the call site, which is
    687                 // initialized with the return value and is destructed later
    688                 // xxx - handle named return values?
    689                 const ast::Type * result = appExpr->result;
    690                 if ( ! result->isVoid() ) {
    691                         static UniqueName retNamer("_tmp_cp_ret");
    692                         auto subResult = env->apply( result ).node;
    693                         auto ret = new ast::ObjectDecl(loc, retNamer.newName(), subResult, nullptr );
    694                         auto mutType = mutate(ret->type.get());
    695                         mutType->set_const( false );
    696                         ret->type = mutType;
    697                         returnDecl = ret;
    698                         stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );
    699                         CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
    700                 } // for
    701                 CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
    702                 // ------------------------------------------------------
    703 
    704                 CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
    705 
    706                 // detach fields from wrapper node so that it can be deleted without deleting too much
    707 
    708                 // xxx - actual env might be somewhere else, need to keep invariant
    709 
    710                 // deletion of wrapper should be handled by pass template now
    711 
    712                 // impCpCtorExpr->callExpr = nullptr;
    713                 assert (appExpr->env == nullptr);
    714                 appExpr->env = impCpCtorExpr->env;
    715                 // std::swap( impCpCtorExpr->env, appExpr->env );
    716                 // assert( impCpCtorExpr->env == nullptr );
    717                 // delete impCpCtorExpr;
    718 
    719                 if ( returnDecl ) {
    720                         ast::Expr * assign = createBitwiseAssignment( new ast::VariableExpr(loc, returnDecl ), appExpr );
    721                         if ( ! dynamic_cast< const ast::ReferenceType * >( result ) ) {
    722                                 // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
    723                                 assign = destructRet( returnDecl, assign );
    724                                 assert(assign);
    725                         } else {
    726                                 assign = new ast::CommaExpr(loc, assign, new ast::VariableExpr(loc, returnDecl ) );
    727                         }
    728                         // move env from appExpr to retExpr
    729                         // std::swap( assign->env, appExpr->env );
    730                         assign->env = appExpr->env;
    731                         // actual env is handled by common routine that replaces WithTypeSubstitution
    732                         return postvisit((const ast::Expr *)assign);
    733                 } else {
    734                         return postvisit((const ast::Expr *)appExpr);
    735                 } // if
    736         }
    737 
    738         const ast::StmtExpr * ResolveCopyCtors::previsit( const ast::StmtExpr * _stmtExpr ) {
    739                 // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
    740                 // since temporaries can be shared across sub-expressions, e.g.
    741                 //   [A, A] f();       // decl
    742                 //   g([A] x, [A] y);  // decl
    743                 //   g(f());           // call
    744                 // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
    745                 // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added
    746                 // to the outer context, rather than inside of the statement expression.
    747 
    748                 // call the common routine that replaces WithTypeSubstitution
    749                 previsit((const ast::Expr *) _stmtExpr);
    750 
    751                 visit_children = false;
    752                 const CodeLocation loc = _stmtExpr->location;
    753 
    754                 assert( env );
    755 
    756                 symtab.enterScope();
    757                 // visit all statements
    758                 auto stmtExpr = mutate(_stmtExpr);
    759                 auto mutStmts = mutate(stmtExpr->stmts.get());
    760 
    761                 auto & stmts = mutStmts->kids;
    762                 for ( auto & stmt : stmts ) {
    763                         stmt = stmt->accept( *visitor );
    764                 } // for
    765                 stmtExpr->stmts = mutStmts;
    766                 symtab.leaveScope();
    767 
    768                 assert( stmtExpr->result );
    769                 // const ast::Type * result = stmtExpr->result;
    770                 if ( ! stmtExpr->result->isVoid() ) {
    771                         static UniqueName retNamer("_tmp_stmtexpr_ret");
    772 
    773                         // result = result->clone();
    774                         auto result = env->apply( stmtExpr->result.get() ).node;
    775                         if ( ! InitTweak::isConstructable( result ) ) {
    776                                 // delete result;
    777                                 return stmtExpr;
    778                         }
    779                         auto mutResult = result.get_and_mutate();
    780                         mutResult->set_const(false);
    781 
    782                         // create variable that will hold the result of the stmt expr
    783                         auto ret = new ast::ObjectDecl(loc, retNamer.newName(), mutResult, nullptr );
    784                         stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );
    785 
    786                         assertf(
    787                                 stmtExpr->resultExpr,
    788                                 "Statement-Expression should have a resulting expression at %s:%d",
    789                                 stmtExpr->location.filename.c_str(),
    790                                 stmtExpr->location.first_line
    791                         );
    792 
    793                         const ast::ExprStmt * last = stmtExpr->resultExpr;
    794                         // xxx - if this is non-unique, need to copy while making resultExpr ref
    795                         assertf(last->unique(), "attempt to modify weakly shared statement");
    796                         auto mutLast = mutate(last);
    797                         // above assertion means in-place mutation is OK
    798                         try {
    799                                 mutLast->expr = makeCtorDtor( "?{}", ret, mutLast->expr );
    800                         } catch(...) {
    801                                 std::cerr << "*CFA internal error: ";
    802                                 std::cerr << "can't resolve implicit constructor";
    803                                 std::cerr << " at " << stmtExpr->location.filename;
    804                                 std::cerr << ":" << stmtExpr->location.first_line << std::endl;
    805 
    806                                 abort();
    807                         }
    808 
    809                         // add destructors after current statement
    810                         stmtsToAddAfter.push_back( new ast::ExprStmt(loc, makeCtorDtor( "^?{}", ret ) ) );
    811 
    812                         // must have a non-empty body, otherwise it wouldn't have a result
    813                         assert( ! stmts.empty() );
    814 
    815                         // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
    816                         stmts.push_back( new ast::ExprStmt(loc, new ast::VariableExpr(loc, ret ) ) );
    817                 } // if
    818 
    819                 assert( stmtExpr->returnDecls.empty() );
    820                 assert( stmtExpr->dtors.empty() );
    821 
    822                 return stmtExpr;
    823         }
    824 
    825         // to prevent warnings ('_unq0' may be used uninitialized in this function),
    826         // insert an appropriate zero initializer for UniqueExpr temporaries.
    827         ast::Init * makeInit( const ast::Type * t, CodeLocation const & loc ) {
    828                 if ( auto inst = dynamic_cast< const ast::StructInstType * >( t ) ) {
    829                         // initizer for empty struct must be empty
    830                         if ( inst->base->members.empty() ) {
    831                                 return new ast::ListInit( loc, {} );
    832                         }
    833                 } else if ( auto inst = dynamic_cast< const ast::UnionInstType * >( t ) ) {
    834                         // initizer for empty union must be empty
    835                         if ( inst->base->members.empty() ) {
    836                                 return new ast::ListInit( loc, {} );
    837                         }
    838                 }
    839 
    840                 return new ast::ListInit( loc, {
    841                         new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) )
    842                 } );
    843         }
    844 
    845         const ast::UniqueExpr * ResolveCopyCtors::previsit( const ast::UniqueExpr * unqExpr ) {
    846                 visit_children = false;
    847                 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
    848                 static std::unordered_map< int, const ast::UniqueExpr * > unqMap;
    849                 auto mutExpr = mutate(unqExpr);
    850                 if ( ! unqMap.count( unqExpr->id ) ) {
    851                         // resolve expr and find its
    852 
    853                         auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>();
    854                         // PassVisitor<ResolveCopyCtors> fixer;
    855 
    856                         mutExpr->expr = mutExpr->expr->accept( *visitor );
    857                         // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
    858                         assert( unqExpr->result );
    859                         if ( impCpCtorExpr ) {
    860                                 auto comma = unqExpr->expr.strict_as<ast::CommaExpr>();
    861                                 auto var = comma->arg2.strict_as<ast::VariableExpr>();
    862                                 // note the variable used as the result from the call
    863                                 mutExpr->var = var;
    864                         } else {
    865                                 // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
    866                                 mutExpr->object = new ast::ObjectDecl( mutExpr->location, toString("_unq", mutExpr->id), mutExpr->result, makeInit( mutExpr->result, mutExpr->location ) );
    867                                 mutExpr->var = new ast::VariableExpr( mutExpr->location, mutExpr->object );
    868                         }
    869 
    870                         unqMap[mutExpr->id] = mutExpr;
    871                 } else {
    872                         // take data from other UniqueExpr to ensure consistency
    873                         // delete unqExpr->get_expr();
    874                         mutExpr->expr = unqMap[mutExpr->id]->expr;
    875                         // delete unqExpr->result;
    876                         mutExpr->result = mutExpr->expr->result;
    877                 }
    878                 return mutExpr;
    879         }
    880 
    881         const ast::DeclWithType * FixInit::postvisit( const ast::ObjectDecl *_objDecl ) {
    882                 const CodeLocation loc = _objDecl->location;
    883 
    884                 // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postvisit)
    885                 if ( ast::ptr<ast::ConstructorInit> ctorInit = _objDecl->init.as<ast::ConstructorInit>() ) {
    886                         auto objDecl = mutate(_objDecl);
    887 
    888                         // could this be non-unique?
    889                         if (objDecl != _objDecl) {
    890                                 std::cerr << "FixInit: non-unique object decl " << objDecl->location << objDecl->name << std::endl;
    891                         }
    892                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    893                         assert( ! ctorInit->ctor || ! ctorInit->init );
    894                         if ( const ast::Stmt * ctor = ctorInit->ctor ) {
    895                                 if ( objDecl->storage.is_static ) {
    896                                         addDataSectionAttribute(objDecl);
    897                                         // originally wanted to take advantage of gcc nested functions, but
    898                                         // we get memory errors with this approach. To remedy this, the static
    899                                         // variable is hoisted when the destructor needs to be called.
    900                                         //
    901                                         // generate:
    902                                         // static T __objName_static_varN;
    903                                         // void __objName_dtor_atexitN() {
    904                                         //   __dtor__...;
    905                                         // }
    906                                         // int f(...) {
    907                                         //   ...
    908                                         //   static bool __objName_uninitialized = true;
    909                                         //   if (__objName_uninitialized) {
    910                                         //     __ctor(__objName);
    911                                         //     __objName_uninitialized = false;
    912                                         //     atexit(__objName_dtor_atexitN);
    913                                         //   }
    914                                         //   ...
    915                                         // }
    916 
    917                                         static UniqueName dtorCallerNamer( "_dtor_atexit" );
    918 
    919                                         // static bool __objName_uninitialized = true
    920                                         auto boolType = new ast::BasicType( ast::BasicType::Kind::Bool );
    921                                         auto boolInitExpr = new ast::SingleInit(loc, ast::ConstantExpr::from_int(loc, 1 ) );
    922                                         auto isUninitializedVar = new ast::ObjectDecl(loc, objDecl->mangleName + "_uninitialized", boolType, boolInitExpr, ast::Storage::Static, ast::Linkage::Cforall);
    923                                         isUninitializedVar->fixUniqueId();
    924 
    925                                         // __objName_uninitialized = false;
    926                                         auto setTrue = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ) );
    927                                         setTrue->args.push_back( new ast::VariableExpr(loc, isUninitializedVar ) );
    928                                         setTrue->args.push_back( ast::ConstantExpr::from_int(loc, 0 ) );
    929 
    930                                         // generate body of if
    931                                         auto initStmts = new ast::CompoundStmt(loc);
    932                                         auto & body = initStmts->kids;
    933                                         body.push_back( ctor );
    934                                         body.push_back( new ast::ExprStmt(loc, setTrue ) );
    935 
    936                                         // put it all together
    937                                         auto ifStmt = new ast::IfStmt(loc, new ast::VariableExpr(loc, isUninitializedVar ), initStmts, 0 );
    938                                         stmtsToAddAfter.push_back( new ast::DeclStmt(loc, isUninitializedVar ) );
    939                                         stmtsToAddAfter.push_back( ifStmt );
    940 
    941                                         const ast::Stmt * dtor = ctorInit->dtor;
    942 
    943                                         // these should be automatically managed once reassigned
    944                                         // objDecl->set_init( nullptr );
    945                                         // ctorInit->set_ctor( nullptr );
    946                                         // ctorInit->set_dtor( nullptr );
    947                                         if ( dtor ) {
    948                                                 // if the object has a non-trivial destructor, have to
    949                                                 // hoist it and the object into the global space and
    950                                                 // call the destructor function with atexit.
    951 
    952                                                 // Statement * dtorStmt = dtor->clone();
    953 
    954                                                 // void __objName_dtor_atexitN(...) {...}
    955                                                 ast::FunctionDecl * dtorCaller = new ast::FunctionDecl(loc, objDecl->mangleName + dtorCallerNamer.newName(), {}, {}, {}, new ast::CompoundStmt(loc, {dtor}), ast::Storage::Static, ast::Linkage::C );
    956                                                 dtorCaller->fixUniqueId();
    957                                                 // dtorCaller->stmts->push_back( dtor );
    958 
    959                                                 // atexit(dtor_atexit);
    960                                                 auto callAtexit = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "atexit" ) );
    961                                                 callAtexit->args.push_back( new ast::VariableExpr(loc, dtorCaller ) );
    962 
    963                                                 body.push_back( new ast::ExprStmt(loc, callAtexit ) );
    964 
    965                                                 // hoist variable and dtor caller decls to list of decls that will be added into global scope
    966                                                 staticDtorDecls.push_back( objDecl );
    967                                                 staticDtorDecls.push_back( dtorCaller );
    968 
    969                                                 // need to rename object uniquely since it now appears
    970                                                 // at global scope and there could be multiple function-scoped
    971                                                 // static variables with the same name in different functions.
    972                                                 // Note: it isn't sufficient to modify only the mangleName, because
    973                                                 // then subsequent Indexer passes can choke on seeing the object's name
    974                                                 // if another object has the same name and type. An unfortunate side-effect
    975                                                 // of renaming the object is that subsequent NameExprs may fail to resolve,
    976                                                 // but there shouldn't be any remaining past this point.
    977                                                 static UniqueName staticNamer( "_static_var" );
    978                                                 objDecl->name = objDecl->name + staticNamer.newName();
    979                                                 objDecl->mangleName = Mangle::mangle( objDecl );
    980                                                 objDecl->init = nullptr;
    981 
    982                                                 // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
    983                                                 // create a new object which is never used
    984                                                 static UniqueName dummyNamer( "_dummy" );
    985                                                 auto dummy = new ast::ObjectDecl(loc, dummyNamer.newName(), new ast::PointerType(new ast::VoidType()), nullptr, ast::Storage::Static, ast::Linkage::Cforall, 0, { new ast::Attribute("unused") } );
    986                                                 // delete ctorInit;
    987                                                 return dummy;
    988                                         } else {
    989                                                 objDecl->init = nullptr;
    990                                                 return objDecl;
    991                                         }
    992                                 } else {
    993                                         auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * > ( ctor );
    994                                         auto ctorStmt = implicit->callStmt.as<ast::ExprStmt>();
    995                                         const ast::ApplicationExpr * ctorCall = nullptr;
    996                                         if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->args.size() == 2 ) {
    997                                                 // clean up intrinsic copy constructor calls by making them into SingleInits
    998                                                 const ast::Expr * ctorArg = ctorCall->args.back();
    999                                                 // ctorCall should be gone afterwards
    1000                                                 auto mutArg = mutate(ctorArg);
    1001                                                 mutArg->env = ctorCall->env;
    1002                                                 // std::swap( ctorArg->env, ctorCall->env );
    1003                                                 objDecl->init = new ast::SingleInit(loc, mutArg );
    1004 
    1005                                                 // ctorCall->args.pop_back();
    1006                                         } else {
    1007                                                 stmtsToAddAfter.push_back( ctor );
    1008                                                 objDecl->init = nullptr;
    1009                                                 // ctorInit->ctor = nullptr;
    1010                                         }
    1011 
    1012                                         const ast::Stmt * dtor = ctorInit->dtor;
    1013                                         if ( dtor ) {
    1014                                                 auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * >( dtor );
    1015                                                 const ast::Stmt * dtorStmt = implicit->callStmt;
    1016 
    1017                                                 // don't need to call intrinsic dtor, because it does nothing, but
    1018                                                 // non-intrinsic dtors must be called
    1019                                                 if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
    1020                                                         // set dtor location to the object's location for error messages
    1021                                                         auto dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
    1022                                                         objDecl->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, dtorFunc ) } ) );
    1023                                                         // ctorInit->dtor = nullptr;
    1024                                                 } // if
    1025                                         }
    1026                                 } // if
    1027                         } else if ( const ast::Init * init = ctorInit->init ) {
    1028                                 objDecl->init = init;
    1029                                 // ctorInit->init = nullptr;
    1030                         } else {
    1031                                 // no constructor and no initializer, which is okay
    1032                                 objDecl->init = nullptr;
    1033                         } // if
    1034                         // delete ctorInit;
    1035                         return objDecl;
    1036                 } // if
    1037                 return _objDecl;
    1038         }
    1039 
    1040         void ObjDeclCollector::previsit( const ast::CompoundStmt * ) {
    1041                 GuardValue( curVars );
    1042         }
    1043 
    1044         void ObjDeclCollector::previsit( const ast::DeclStmt * stmt ) {
    1045                 // keep track of all variables currently in scope
    1046                 if ( auto objDecl = stmt->decl.as<ast::ObjectDecl>() ) {
    1047                         curVars.push_back( objDecl );
    1048                 } // if
    1049         }
    1050 
    1051         void LabelFinder::previsit( const ast::Stmt * stmt ) {
    1052                 // for each label, remember the variables in scope at that label.
    1053                 for ( auto l : stmt->labels ) {
    1054                         vars[l] = curVars;
    1055                 } // for
    1056         }
    1057 
    1058         void LabelFinder::previsit( const ast::CompoundStmt * stmt ) {
    1059                 previsit( (const ast::Stmt *) stmt );
    1060                 Parent::previsit( stmt );
    1061         }
    1062 
    1063         void LabelFinder::previsit( const ast::DeclStmt * stmt ) {
    1064                 previsit( (const ast::Stmt *)stmt );
    1065                 Parent::previsit( stmt );
    1066         }
    1067 
    1068 
    1069         void InsertDtors::previsit( const ast::FunctionDecl * funcDecl ) {
    1070                 // each function needs to have its own set of labels
    1071                 GuardValue( labelVars );
    1072                 labelVars.clear();
    1073                 // LabelFinder does not recurse into FunctionDecl, so need to visit
    1074                 // its children manually.
    1075                 if (funcDecl->type) funcDecl->type->accept(finder);
    1076                 // maybeAccept( funcDecl->type, finder );
    1077                 if (funcDecl->stmts) funcDecl->stmts->accept(finder) ;
    1078 
    1079                 // all labels for this function have been collected, insert destructors as appropriate via implicit recursion.
    1080         }
    1081 
    1082         // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    1083         // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
    1084         // at the target location but not at the BranchStmt then those objects would be uninitialized so notify the user
    1085         // of the error.  See C++ Reference 6.6 Jump Statements for details.
    1086         void InsertDtors::handleGoto( const ast::BranchStmt * stmt ) {
    1087                 // can't do anything for computed goto
    1088                 if ( stmt->computedTarget ) return;
    1089 
    1090                 assertf( stmt->target.name != "", "BranchStmt missing a label: %s", toString( stmt ).c_str() );
    1091                 // S_L = lvars = set of objects in scope at label definition
    1092                 // S_G = curVars = set of objects in scope at goto statement
    1093                 ObjectSet & lvars = labelVars[ stmt->target ];
    1094 
    1095                 DTOR_PRINT(
    1096                         std::cerr << "at goto label: " << stmt->target.name << std::endl;
    1097                         std::cerr << "S_G = " << printSet( curVars ) << std::endl;
    1098                         std::cerr << "S_L = " << printSet( lvars ) << std::endl;
    1099                 )
    1100 
    1101 
    1102                 // std::set_difference requires that the inputs be sorted.
    1103                 lvars.sort();
    1104                 curVars.sort();
    1105 
    1106                 ObjectSet diff;
    1107                 // S_L-S_G results in set of objects whose construction is skipped - it's an error if this set is non-empty
    1108                 std::set_difference( lvars.begin(), lvars.end(), curVars.begin(), curVars.end(), std::inserter( diff, diff.begin() ) );
    1109                 DTOR_PRINT(
    1110                         std::cerr << "S_L-S_G = " << printSet( diff ) << std::endl;
    1111                 )
    1112                 if ( ! diff.empty() ) {
    1113                         SemanticError( stmt, std::string("jump to label '") + stmt->target.name + "' crosses initialization of " + (*diff.begin())->name + " " );
    1114                 } // if
    1115         }
    1116 
    1117         void InsertDtors::previsit( const ast::BranchStmt * stmt ) {
    1118                 switch( stmt->kind ) {
    1119                 case ast::BranchStmt::Continue:
    1120                 case ast::BranchStmt::Break:
    1121                         // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
    1122                         // always be empty), but it serves as a small sanity check.
    1123                 case ast::BranchStmt::Goto:
    1124                         handleGoto( stmt );
    1125                         break;
    1126                 default:
    1127                         assert( false );
    1128                 } // switch
    1129         }
    1130 
    1131         bool checkWarnings( const ast::FunctionDecl * funcDecl ) {
    1132                 // only check for warnings if the current function is a user-defined
    1133                 // constructor or destructor
    1134                 if ( ! funcDecl ) return false;
    1135                 if ( ! funcDecl->stmts ) return false;
    1136                 return CodeGen::isCtorDtor( funcDecl->name ) && ! funcDecl->linkage.is_overrideable;
    1137         }
    1138 
    1139         void GenStructMemberCalls::previsit( const ast::FunctionDecl * funcDecl ) {
    1140                 GuardValue( function );
    1141                 GuardValue( unhandled );
    1142                 GuardValue( usedUninit );
    1143                 GuardValue( thisParam );
    1144                 GuardValue( isCtor );
    1145                 GuardValue( structDecl );
    1146                 errors = SemanticErrorException();  // clear previous errors
    1147 
    1148                 // need to start with fresh sets
    1149                 unhandled.clear();
    1150                 usedUninit.clear();
    1151 
    1152                 function = mutate(funcDecl);
    1153                 // could this be non-unique?
    1154                 if (function != funcDecl) {
    1155                         std::cerr << "GenStructMemberCalls: non-unique FunctionDecl " << funcDecl->location << funcDecl->name << std::endl;
    1156                 }
    1157 
    1158                 isCtor = CodeGen::isConstructor( function->name );
    1159                 if ( checkWarnings( function ) ) {
    1160                         // const ast::FunctionType * type = function->type;
    1161                         // assert( ! type->params.empty() );
    1162                         thisParam = function->params.front().strict_as<ast::ObjectDecl>();
    1163                         auto thisType = getPointerBase( thisParam->get_type() );
    1164                         auto structType = dynamic_cast< const ast::StructInstType * >( thisType );
    1165                         if ( structType ) {
    1166                                 structDecl = structType->base;
    1167                                 for ( auto & member : structDecl->members ) {
    1168                                         if ( auto field = member.as<ast::ObjectDecl>() ) {
    1169                                                 // record all of the struct type's members that need to be constructed or
    1170                                                 // destructed by the end of the function
    1171                                                 unhandled.insert( field );
    1172                                         }
    1173                                 }
    1174                         }
    1175                 }
    1176         }
    1177 
    1178         const ast::DeclWithType * GenStructMemberCalls::postvisit( const ast::FunctionDecl * funcDecl ) {
    1179                 // remove the unhandled objects from usedUninit, because a call is inserted
    1180                 // to handle them - only objects that are later constructed are used uninitialized.
    1181                 std::map< const ast::DeclWithType *, CodeLocation > diff;
    1182                 // need the comparator since usedUninit and unhandled have different types
    1183                 struct comp_t {
    1184                         typedef decltype(usedUninit)::value_type usedUninit_t;
    1185                         typedef decltype(unhandled)::value_type unhandled_t;
    1186                         bool operator()(usedUninit_t x, unhandled_t y) { return x.first < y; }
    1187                         bool operator()(unhandled_t x, usedUninit_t y) { return x < y.first; }
    1188                 } comp;
    1189                 std::set_difference( usedUninit.begin(), usedUninit.end(), unhandled.begin(), unhandled.end(), std::inserter( diff, diff.begin() ), comp );
    1190                 for ( auto p : diff ) {
    1191                         auto member = p.first;
    1192                         auto loc = p.second;
    1193                         // xxx - make error message better by also tracking the location that the object is constructed at?
    1194                         emit( loc, "in ", function->name, ", field ", member->name, " used before being constructed" );
    1195                 }
    1196 
    1197                 const CodeLocation loc = funcDecl->location;
    1198 
    1199                 if ( ! unhandled.empty() ) {
    1200                         auto mutStmts = function->stmts.get_and_mutate();
    1201                         // need to explicitly re-add function parameters to the indexer in order to resolve copy constructors
    1202                         auto guard = makeFuncGuard( [this]() { symtab.enterScope(); }, [this]() { symtab.leaveScope(); } );
    1203                         symtab.addFunction( function );
    1204                         auto global = transUnit().global;
    1205 
    1206                         // need to iterate through members in reverse in order for
    1207                         // ctor/dtor statements to come out in the right order
    1208                         for ( auto & member : reverseIterate( structDecl->members ) ) {
    1209                                 auto field = member.as<ast::ObjectDecl>();
    1210                                 // skip non-DWT members
    1211                                 if ( ! field ) continue;
    1212                                 // skip non-constructable members
    1213                                 if ( ! tryConstruct( field ) ) continue;
    1214                                 // skip handled members
    1215                                 if ( ! unhandled.count( field ) ) continue;
    1216 
    1217                                 // insert and resolve default/copy constructor call for each field that's unhandled
    1218                                 // std::list< const ast::Stmt * > stmt;
    1219                                 ast::Expr * arg2 = nullptr;
    1220                                 if ( function->name == "?{}" && isCopyFunction( function ) ) {
    1221                                         // if copy ctor, need to pass second-param-of-this-function.field
    1222                                         // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
    1223                                         assert( function->params.size() == 2 );
    1224                                         arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) );
    1225                                 }
    1226                                 InitExpander_new srcParam( arg2 );
    1227                                 // cast away reference type and construct field.
    1228                                 ast::Expr * thisExpr = new ast::CastExpr(funcDecl->location, new ast::VariableExpr(funcDecl->location, thisParam ), thisParam->get_type()->stripReferences());
    1229                                 ast::Expr * memberDest = new ast::MemberExpr(funcDecl->location, field, thisExpr );
    1230                                 ast::ptr<ast::Stmt> callStmt = SymTab::genImplicitCall( srcParam, memberDest, loc, function->name, field, static_cast<SymTab::LoopDirection>(isCtor) );
    1231 
    1232                                 if ( callStmt ) {
    1233                                         // auto & callStmt = stmt.front();
    1234 
    1235                                         try {
    1236                                                 callStmt = callStmt->accept( *visitor );
    1237                                                 if ( isCtor ) {
    1238                                                         mutStmts->push_front( callStmt );
    1239                                                 } else { // TODO: don't generate destructor function/object for intrinsic calls
    1240                                                         // destructor statements should be added at the end
    1241                                                         // function->get_statements()->push_back( callStmt );
    1242 
    1243                                                         // Optimization: do not need to call intrinsic destructors on members
    1244                                                         if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue;
    1245 
    1246                                                         // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };
    1247                                                         std::list< ast::ptr<ast::Stmt> > stmtsToAdd;
    1248 
    1249                                                         static UniqueName memberDtorNamer = { "__memberDtor" };
    1250                                                         assertf( global.dtorStruct, "builtin __Destructor not found." );
    1251                                                         assertf( global.dtorDestroy, "builtin __destroy_Destructor not found." );
    1252 
    1253                                                         ast::Expr * thisExpr = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, thisParam ) ), new ast::PointerType( new ast::VoidType(), ast::CV::Qualifiers() ) );
    1254                                                         ast::Expr * dtorExpr = new ast::VariableExpr(loc, getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
    1255 
    1256                                                         // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
    1257                                                         auto dtorFtype = new ast::FunctionType();
    1258                                                         dtorFtype->params.emplace_back( new ast::PointerType( new ast::VoidType() ) );
    1259                                                         auto dtorType = new ast::PointerType( dtorFtype );
    1260 
    1261                                                         auto destructor = new ast::ObjectDecl(loc, memberDtorNamer.newName(), new ast::StructInstType( global.dtorStruct ), new ast::ListInit(loc, { new ast::SingleInit(loc, thisExpr ), new ast::SingleInit(loc, new ast::CastExpr( dtorExpr, dtorType ) ) } ) );
    1262                                                         destructor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr( loc, global.dtorDestroy ) } ) );
    1263                                                         mutStmts->push_front( new ast::DeclStmt(loc, destructor ) );
    1264                                                         mutStmts->kids.splice( mutStmts->kids.begin(), stmtsToAdd );
    1265                                                 }
    1266                                         } catch ( SemanticErrorException & error ) {
    1267                                                 emit( funcDecl->location, "in ", function->name , ", field ", field->name, " not explicitly ", isCtor ? "constructed" : "destructed",  " and no ", isCtor ? "default constructor" : "destructor", " found" );
    1268                                         }
    1269                                 }
    1270                         }
    1271                         function->stmts = mutStmts;
    1272                 }
    1273                 if (! errors.isEmpty()) {
    1274                         throw errors;
    1275                 }
    1276                 // return funcDecl;
    1277                 return function;
    1278         }
    1279 
    1280         /// true if expr is effectively just the 'this' parameter
    1281         bool isThisExpression( const ast::Expr * expr, const ast::DeclWithType * thisParam ) {
    1282                 // TODO: there are more complicated ways to pass 'this' to a constructor, e.g. &*, *&, etc.
    1283                 if ( auto varExpr = dynamic_cast< const ast::VariableExpr * >( expr ) ) {
    1284                         return varExpr->var == thisParam;
    1285                 } else if ( auto castExpr = dynamic_cast< const ast::CastExpr * > ( expr ) ) {
    1286                         return isThisExpression( castExpr->arg, thisParam );
    1287                 }
    1288                 return false;
    1289         }
    1290 
    1291         /// returns a MemberExpr if expr is effectively just member access on the 'this' parameter, else nullptr
    1292         const ast::MemberExpr * isThisMemberExpr( const ast::Expr * expr, const ast::DeclWithType * thisParam ) {
    1293                 if ( auto memberExpr = dynamic_cast< const ast::MemberExpr * >( expr ) ) {
    1294                         if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
    1295                                 return memberExpr;
    1296                         }
    1297                 } else if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {
    1298                         return isThisMemberExpr( castExpr->arg, thisParam );
    1299                 }
    1300                 return nullptr;
    1301         }
    1302 
    1303         void GenStructMemberCalls::previsit( const ast::ApplicationExpr * appExpr ) {
    1304                 if ( ! checkWarnings( function ) ) {
    1305                         visit_children = false;
    1306                         return;
    1307                 }
    1308 
    1309                 std::string fname = getFunctionName( appExpr );
    1310                 if ( fname == function->name ) {
    1311                         // call to same kind of function
    1312                         const ast::Expr * firstParam = appExpr->args.front();
    1313 
    1314                         if ( isThisExpression( firstParam, thisParam ) ) {
    1315                                 // if calling another constructor on thisParam, assume that function handles
    1316                                 // all members - if it doesn't a warning will appear in that function.
    1317                                 unhandled.clear();
    1318                         } else if ( auto memberExpr = isThisMemberExpr( firstParam, thisParam ) ) {
    1319                                 // if first parameter is a member expression on the this parameter,
    1320                                 // then remove the member from unhandled set.
    1321                                 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
    1322                                         unhandled.erase( memberExpr->member );
    1323                                 }
    1324                         }
    1325                 }
    1326         }
    1327 
    1328         void GenStructMemberCalls::previsit( const ast::MemberExpr * memberExpr ) {
    1329                 if ( ! checkWarnings( function ) || ! isCtor ) {
    1330                         visit_children = false;
    1331                         return;
    1332                 }
    1333 
    1334                 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
    1335                         if ( unhandled.count( memberExpr->member ) ) {
    1336                                 // emit a warning because a member was used before it was constructed
    1337                                 usedUninit.insert( { memberExpr->member, memberExpr->location } );
    1338                         }
    1339                 }
    1340         }
    1341 
    1342         template< typename... Params >
    1343         void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
    1344                 SemanticErrorException err( loc, toString( params... ) );
    1345                 errors.append( err );
    1346         }
    1347 
    1348         const ast::Expr * GenStructMemberCalls::postvisit( const ast::UntypedExpr * untypedExpr ) {
    1349                 // xxx - functions returning ast::ptr seems wrong...
    1350                 auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
    1351                 return res.release();
    1352         }
    1353 
    1354         void InsertImplicitCalls::previsit(const ast::UniqueExpr * unqExpr) {
    1355                 if (visitedIds.count(unqExpr->id)) visit_children = false;
    1356                 else visitedIds.insert(unqExpr->id);
    1357         }
    1358 
    1359         const ast::Expr * FixCtorExprs::postvisit( const ast::ConstructorExpr * ctorExpr ) {
    1360                 const CodeLocation loc = ctorExpr->location;
    1361                 static UniqueName tempNamer( "_tmp_ctor_expr" );
    1362                 // xxx - is the size check necessary?
    1363                 assert( ctorExpr->result && ctorExpr->result->size() == 1 );
    1364 
    1365                 // xxx - this can be TupleAssignExpr now. Need to properly handle this case.
    1366                 // take possession of expr and env
    1367                 ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>();
    1368                 ast::ptr<ast::TypeSubstitution> env = ctorExpr->env;
    1369                 // ctorExpr->set_callExpr( nullptr );
    1370                 // ctorExpr->set_env( nullptr );
    1371 
    1372                 // xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary.
    1373                 auto tmp = new ast::ObjectDecl(loc, tempNamer.newName(), callExpr->args.front()->result );
    1374                 declsToAddBefore.push_back( tmp );
    1375 
    1376                 // build assignment and replace constructor's first argument with new temporary
    1377                 auto mutCallExpr = callExpr.get_and_mutate();
    1378                 const ast::Expr * firstArg = callExpr->args.front();
    1379                 ast::Expr * assign = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ), { new ast::AddressExpr(loc, new ast::VariableExpr(loc, tmp ) ), new ast::AddressExpr( firstArg ) } );
    1380                 firstArg = new ast::VariableExpr(loc, tmp );
    1381                 mutCallExpr->args.front() = firstArg;
    1382 
    1383                 // resolve assignment and dispose of new env
    1384                 auto resolved = ResolvExpr::findVoidExpression( assign, { symtab, transUnit().global } );
    1385                 auto mut = resolved.get_and_mutate();
    1386                 assertf(resolved.get() == mut, "newly resolved expression must be unique");
    1387                 mut->env = nullptr;
    1388 
    1389                 // for constructor expr:
    1390                 //   T x;
    1391                 //   x{};
    1392                 // results in:
    1393                 //   T x;
    1394                 //   T & tmp;
    1395                 //   &tmp = &x, ?{}(tmp), tmp
    1396                 ast::CommaExpr * commaExpr = new ast::CommaExpr(loc, resolved, new ast::CommaExpr(loc, mutCallExpr, new ast::VariableExpr(loc, tmp ) ) );
    1397                 commaExpr->env = env;
    1398                 return commaExpr;
    1399         }
    1400 } // namespace
    14011382} // namespace InitTweak
    14021383
  • src/InitTweak/GenInit.cc

    r92355883 r2a301ff  
    300300
    301301#       warning Remove the _New suffix after the conversion is complete.
     302
     303        // Outer pass finds declarations, for their type could wrap a type that needs hoisting
    302304        struct HoistArrayDimension_NoResolve_New final :
    303305                        public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
    304306                        public ast::WithGuards, public ast::WithConstTranslationUnit,
    305                         public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> {
    306                 void previsit( const ast::ObjectDecl * decl );
    307                 const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl );
    308                 // Do not look for objects inside there declarations (and type).
    309                 void previsit( const ast::AggregateDecl * ) { visit_children = false; }
    310                 void previsit( const ast::NamedTypeDecl * ) { visit_children = false; }
    311                 void previsit( const ast::FunctionType * ) { visit_children = false; }
    312 
    313                 const ast::Type * hoist( const ast::Type * type );
     307                        public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New>,
     308                        public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> {
     309
     310                // Inner pass looks within a type, for a part that depends on an expression
     311                struct HoistDimsFromTypes final :
     312                                public ast::WithShortCircuiting, public ast::WithGuards {
     313
     314                        HoistArrayDimension_NoResolve_New * outer;
     315                        HoistDimsFromTypes( HoistArrayDimension_NoResolve_New * outer ) : outer(outer) {}
     316
     317                        // Only intended for visiting through types.
     318                        // Tolerate, and short-circuit at, the dimension expression of an array type.
     319                        //    (We'll operate on the dimension expression of an array type directly
     320                        //    from the parent type, not by visiting through it)
     321                        // Look inside type exprs.
     322                        void previsit( const ast::Node * ) {
     323                                assert( false && "unsupported node type" );
     324                        };
     325                        const ast::Expr * allowedExpr = nullptr;
     326                        void previsit( const ast::Type * ) {
     327                                GuardValue( allowedExpr ) = nullptr;
     328                        }
     329                        void previsit( const ast::ArrayType * t ) {
     330                                GuardValue( allowedExpr ) = t->dimension.get();
     331                        }
     332                        void previsit( const ast::PointerType * t ) {
     333                                GuardValue( allowedExpr ) = t->dimension.get();
     334                        }
     335                        void previsit( const ast::TypeofType * t ) {
     336                                GuardValue( allowedExpr ) = t->expr.get();
     337                        }
     338                        void previsit( const ast::Expr * e ) {
     339                                assert( e == allowedExpr &&
     340                                    "only expecting to visit exprs that are dimension exprs or typeof(-) inner exprs" );
     341
     342                                // Skip the tolerated expressions
     343                                visit_children = false;
     344                        }
     345                        void previsit( const ast::TypeExpr * ) {}
     346
     347                        const ast::Type * postvisit(
     348                                        const ast::ArrayType * arrayType ) {
     349                                static UniqueName dimensionName( "_array_dim" );
     350
     351                                if ( nullptr == arrayType->dimension ) {  // if no dimension is given, don't presume to invent one
     352                                        return arrayType;
     353                                }
     354
     355                                // find size_t; use it as the type for a dim expr
     356                                ast::ptr<ast::Type> dimType = outer->transUnit().global.sizeType;
     357                                assert( dimType );
     358                                add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
     359
     360                                // Special-case handling: leave the user's dimension expression alone
     361                                // - requires the user to have followed a careful convention
     362                                // - may apply to extremely simple applications, but only as windfall
     363                                // - users of advanced applications will be following the convention on purpose
     364                                // - CFA maintainers must protect the criteria against leaving too much alone
     365
     366                                // Actual leave-alone cases following are conservative approximations of "cannot vary"
     367
     368                                // Leave alone: literals and enum constants
     369                                if ( dynamic_cast< const ast::ConstantExpr * >( arrayType->dimension.get() ) ) {
     370                                        return arrayType;
     371                                }
     372
     373                                // Leave alone: direct use of an object declared to be const
     374                                const ast::NameExpr * dimn = dynamic_cast< const ast::NameExpr * >( arrayType->dimension.get() );
     375                                if ( dimn ) {
     376                                        std::vector<ast::SymbolTable::IdData> dimnDefs = outer->symtab.lookupId( dimn->name );
     377                                        if ( dimnDefs.size() == 1 ) {
     378                                                const ast::DeclWithType * dimnDef = dimnDefs[0].id.get();
     379                                                assert( dimnDef && "symbol table binds a name to nothing" );
     380                                                const ast::ObjectDecl * dimOb = dynamic_cast< const ast::ObjectDecl * >( dimnDef );
     381                                                if( dimOb ) {
     382                                                        const ast::Type * dimTy = dimOb->type.get();
     383                                                        assert( dimTy && "object declaration bearing no type" );
     384                                                        // must not hoist some: size_t
     385                                                        // must hoist all: pointers and references
     386                                                        // the analysis is conservative; BasicType is a simple approximation
     387                                                        if ( dynamic_cast< const ast::BasicType * >( dimTy ) ||
     388                                                             dynamic_cast< const ast::SueInstType<ast::EnumDecl> * >( dimTy ) ) {
     389                                                                if ( dimTy->is_const() ) {
     390                                                                        // The dimension is certainly re-evaluable, giving the same answer each time.
     391                                                                        // Our user might be hoping to write the array type in multiple places, having them unify.
     392                                                                        // Leave the type alone.
     393
     394                                                                        // We believe the new criterion leaves less alone than the old criterion.
     395                                                                        // Thus, the old criterion should have left the current case alone.
     396                                                                        // Catch cases that weren't thought through.
     397                                                                        assert( !Tuples::maybeImpure( arrayType->dimension ) );
     398
     399                                                                        return arrayType;
     400                                                                }
     401                                                        };
     402                                                }
     403                                        }
     404                                }
     405
     406                                // Leave alone: any sizeof expression (answer cannot vary during current lexical scope)
     407                                const ast::SizeofExpr * sz = dynamic_cast< const ast::SizeofExpr * >( arrayType->dimension.get() );
     408                                if ( sz ) {
     409                                        return arrayType;
     410                                }
     411
     412                                // General-case handling: change the array-type's dim expr (hoist the user-given content out of the type)
     413                                // - always safe
     414                                // - user-unnoticeable in common applications (benign noise in -CFA output)
     415                                // - may annoy a responsible user of advanced applications (but they can work around)
     416                                // - protects against misusing advanced features
     417                                //
     418                                // The hoist, by example, is:
     419                                // FROM USER:  float a[ rand() ];
     420                                // TO GCC:     const size_t __len_of_a = rand(); float a[ __len_of_a ];
     421
     422                                ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
     423                                        arrayType->dimension->location,
     424                                        dimensionName.newName(),
     425                                        dimType,
     426                                        new ast::SingleInit(
     427                                                arrayType->dimension->location,
     428                                                arrayType->dimension
     429                                        )
     430                                );
     431
     432                                ast::ArrayType * mutType = ast::mutate( arrayType );
     433                                mutType->dimension = new ast::VariableExpr(
     434                                                arrayDimension->location, arrayDimension );
     435                                outer->declsToAddBefore.push_back( arrayDimension );
     436
     437                                return mutType;
     438                        }  // postvisit( const ast::ArrayType * )
     439                }; // struct HoistDimsFromTypes
    314440
    315441                ast::Storage::Classes storageClasses;
     442                void previsit(
     443                                const ast::ObjectDecl * decl ) {
     444                        GuardValue( storageClasses ) = decl->storage;
     445                }
     446
     447                const ast::DeclWithType * postvisit(
     448                                const ast::ObjectDecl * objectDecl ) {
     449
     450                        if ( !isInFunction() || storageClasses.is_static ) {
     451                                return objectDecl;
     452                        }
     453
     454                        const ast::Type * mid = objectDecl->type;
     455
     456                        ast::Pass<HoistDimsFromTypes> hoist{this};
     457                        const ast::Type * result = mid->accept( hoist );
     458
     459                        return mutate_field( objectDecl, &ast::ObjectDecl::type, result );
     460                }
    316461        };
    317462
    318         void HoistArrayDimension_NoResolve_New::previsit(
    319                         const ast::ObjectDecl * decl ) {
    320                 GuardValue( storageClasses ) = decl->storage;
    321         }
    322 
    323         const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit(
    324                         const ast::ObjectDecl * objectDecl ) {
    325                 return mutate_field( objectDecl, &ast::ObjectDecl::type,
    326                                 hoist( objectDecl->type ) );
    327         }
    328 
    329         const ast::Type * HoistArrayDimension_NoResolve_New::hoist(
    330                         const ast::Type * type ) {
    331                 static UniqueName dimensionName( "_array_dim" );
    332 
    333                 if ( !isInFunction() || storageClasses.is_static ) {
    334                         return type;
    335                 }
    336 
    337                 if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
    338                         if ( nullptr == arrayType->dimension ) {
    339                                 return type;
    340                         }
    341 
    342                         if ( !Tuples::maybeImpure( arrayType->dimension ) ) {
    343                                 return type;
    344                         }
    345 
    346                         ast::ptr<ast::Type> dimType = transUnit().global.sizeType;
    347                         assert( dimType );
    348                         add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
    349 
    350                         ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
    351                                 arrayType->dimension->location,
    352                                 dimensionName.newName(),
    353                                 dimType,
    354                                 new ast::SingleInit(
    355                                         arrayType->dimension->location,
    356                                         arrayType->dimension
    357                                 )
    358                         );
    359 
    360                         ast::ArrayType * mutType = ast::mutate( arrayType );
    361                         mutType->dimension = new ast::VariableExpr(
    362                                         arrayDimension->location, arrayDimension );
    363                         declsToAddBefore.push_back( arrayDimension );
    364 
    365                         mutType->base = hoist( mutType->base );
    366                         return mutType;
    367                 }
    368                 return type;
    369         }
     463
     464
    370465
    371466        struct ReturnFixer_New final :
  • src/InitTweak/InitTweak.cc

    r92355883 r2a301ff  
    882882                if (!assign) {
    883883                        auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true);
    884                         assign = new ast::FunctionDecl(CodeLocation(), "?=?", {},
     884                        assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td},
    885885                        { new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
    886886                          new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))},
     
    891891                                dst = new ast::AddressExpr(dst);
    892892                        }
    893                 }
    894                 else {
     893                } else {
    895894                        dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
    896895                }
     
    900899                        }
    901900                }
    902                 return new ast::ApplicationExpr(dst->location, ast::VariableExpr::functionPointer(dst->location, assign), {dst, src});
     901                auto var = ast::VariableExpr::functionPointer(dst->location, assign);
     902                auto app = new ast::ApplicationExpr(dst->location, var, {dst, src});
     903                // Skip the resolver, just set the result to the correct type.
     904                app->result = ast::deepCopy( src->result );
     905                return app;
    903906        }
    904907
  • src/Parser/StatementNode.cc

    r92355883 r2a301ff  
    1010// Author           : Rodolfo G. Esteves
    1111// Created On       : Sat May 16 14:59:41 2015
    12 // Last Modified By : Andrew Beach
    13 // Last Modified On : Tue Apr 11 10:16:00 2023
    14 // Update Count     : 428
     12// Last Modified By : Peter A. Buhr
     13// Last Modified On : Fri Aug 11 11:44:15 2023
     14// Update Count     : 429
    1515//
    1616
     
    361361
    362362ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
    363     ast::WhenClause * clause = new ast::WhenClause( loc );
    364     clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    365     clause->stmt = maybeMoveBuild( stmt );
    366     clause->target = maybeMoveBuild( targetExpr );
    367     return new ast::WaitUntilStmt::ClauseNode( clause );
     363        ast::WhenClause * clause = new ast::WhenClause( loc );
     364        clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     365        clause->stmt = maybeMoveBuild( stmt );
     366        clause->target = maybeMoveBuild( targetExpr );
     367        return new ast::WaitUntilStmt::ClauseNode( clause );
    368368}
    369369ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
    370     ast::WhenClause * clause = new ast::WhenClause( loc );
    371     clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    372     clause->stmt = maybeMoveBuild( stmt );
    373     return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
    374 }
    375 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
    376     ast::WhenClause * clause = new ast::WhenClause( loc );
    377     clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    378     clause->stmt = maybeMoveBuild( stmt );
    379     clause->target = maybeMoveBuild( timeout );
    380     return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::TIMEOUT, clause );
     370        ast::WhenClause * clause = new ast::WhenClause( loc );
     371        clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     372        clause->stmt = maybeMoveBuild( stmt );
     373        return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
    381374}
    382375
    383376ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) {
    384     ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );
    385     retStmt->predicateTree = root;
    386    
    387     // iterative tree traversal
    388     std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal
    389     ast::WaitUntilStmt::ClauseNode * currNode = nullptr;
    390     ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;
    391     ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout
    392     nodeStack.push_back(root);
    393 
    394     do {
    395         currNode = nodeStack.back();
    396         nodeStack.pop_back(); // remove node since it will be processed
    397 
    398         switch (currNode->op) {
    399             case ast::WaitUntilStmt::ClauseNode::LEAF:
    400                 retStmt->clauses.push_back(currNode->leaf);
    401                 break;
    402             case ast::WaitUntilStmt::ClauseNode::ELSE:
    403                 retStmt->else_stmt = currNode->leaf->stmt
    404                     ? ast::deepCopy( currNode->leaf->stmt )
    405                     : nullptr;
    406                
    407                 retStmt->else_cond = currNode->leaf->when_cond
    408                     ? ast::deepCopy( currNode->leaf->when_cond )
    409                     : nullptr;
    410 
    411                 delete currNode->leaf;
    412                 break;
    413             case ast::WaitUntilStmt::ClauseNode::TIMEOUT:
    414                 retStmt->timeout_time = currNode->leaf->target
    415                     ? ast::deepCopy( currNode->leaf->target )
    416                     : nullptr;
    417                 retStmt->timeout_stmt = currNode->leaf->stmt
    418                     ? ast::deepCopy( currNode->leaf->stmt )
    419                     : nullptr;
    420                 retStmt->timeout_cond = currNode->leaf->when_cond
    421                     ? ast::deepCopy( currNode->leaf->when_cond )
    422                     : nullptr;
    423 
    424                 delete currNode->leaf;
    425                 break;
    426             default:
    427                 nodeStack.push_back( currNode->right ); // process right after left
    428                 nodeStack.push_back( currNode->left );
    429 
    430                 // Cut else/timeout out of the tree
    431                 if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {
    432                     if ( lastInternalNode )
    433                         lastInternalNode->right = currNode->left;
    434                     else    // if not set then root is LEFT_OR
    435                         retStmt->predicateTree = currNode->left;
    436    
    437                     currNode->left = nullptr;
    438                     cleanup = currNode;
    439                 }
    440                
    441                 lastInternalNode = currNode;
    442                 break;
    443         }
    444     } while ( !nodeStack.empty() );
    445 
    446     if ( cleanup ) delete cleanup;
    447 
    448     return retStmt;
     377        ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );
     378        retStmt->predicateTree = root;
     379
     380        // iterative tree traversal
     381        std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal
     382        ast::WaitUntilStmt::ClauseNode * currNode = nullptr;
     383        ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;
     384        ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout
     385        nodeStack.push_back(root);
     386
     387        do {
     388                currNode = nodeStack.back();
     389                nodeStack.pop_back(); // remove node since it will be processed
     390
     391                switch (currNode->op) {
     392                case ast::WaitUntilStmt::ClauseNode::LEAF:
     393                        retStmt->clauses.push_back(currNode->leaf);
     394                        break;
     395                case ast::WaitUntilStmt::ClauseNode::ELSE:
     396                        retStmt->else_stmt = currNode->leaf->stmt
     397                                ? ast::deepCopy( currNode->leaf->stmt )
     398                                : nullptr;
     399                        retStmt->else_cond = currNode->leaf->when_cond
     400                                ? ast::deepCopy( currNode->leaf->when_cond )
     401                                : nullptr;
     402
     403                        delete currNode->leaf;
     404                        break;
     405                case ast::WaitUntilStmt::ClauseNode::TIMEOUT:
     406                        retStmt->timeout_time = currNode->leaf->target
     407                                ? ast::deepCopy( currNode->leaf->target )
     408                                : nullptr;
     409                        retStmt->timeout_stmt = currNode->leaf->stmt
     410                                ? ast::deepCopy( currNode->leaf->stmt )
     411                                : nullptr;
     412                        retStmt->timeout_cond = currNode->leaf->when_cond
     413                                ? ast::deepCopy( currNode->leaf->when_cond )
     414                                : nullptr;
     415
     416                        delete currNode->leaf;
     417                        break;
     418                default:
     419                        nodeStack.push_back( currNode->right ); // process right after left
     420                        nodeStack.push_back( currNode->left );
     421
     422                        // Cut else/timeout out of the tree
     423                        if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {
     424                                if ( lastInternalNode )
     425                                        lastInternalNode->right = currNode->left;
     426                                else // if not set then root is LEFT_OR
     427                                        retStmt->predicateTree = currNode->left;
     428
     429                                currNode->left = nullptr;
     430                                cleanup = currNode;
     431                        }
     432
     433                        lastInternalNode = currNode;
     434                        break;
     435                }
     436        } while ( !nodeStack.empty() );
     437
     438        if ( cleanup ) delete cleanup;
     439
     440        return retStmt;
    449441}
    450442
  • src/Parser/StatementNode.h

    r92355883 r2a301ff  
    99// Author           : Andrew Beach
    1010// Created On       : Wed Apr  5 11:42:00 2023
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr 11  9:43:00 2023
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Aug 11 11:44:07 2023
     13// Update Count     : 2
    1414//
    1515
     
    102102ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
    103103ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );
    104 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
    105104ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );
    106105ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
  • src/Parser/TypedefTable.cc

    r92355883 r2a301ff  
    1010// Created On       : Sat May 16 15:20:13 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 15 08:27:24 2022
    13 // Update Count     : 275
     12// Last Modified On : Wed Jul 12 06:11:28 2023
     13// Update Count     : 276
    1414//
    1515
     
    1717#include "TypedefTable.h"
    1818
    19 #include <cassert>                                // for assert
    20 #include <string>                                 // for string
    21 #include <iostream>                               // for iostream
     19#include <cassert>                                                                              // for assert
     20#include <string>                                                                               // for string
     21#include <iostream>                                                                             // for iostream
    2222
    23 #include "ExpressionNode.h"                       // for LabelNode
    24 #include "ParserTypes.h"                          // for Token
    25 #include "StatementNode.h"                        // for CondCtl, ForCtrl
     23#include "ExpressionNode.h"                                                             // for LabelNode
     24#include "ParserTypes.h"                                                                // for Token
     25#include "StatementNode.h"                                                              // for CondCtl, ForCtrl
    2626// This (generated) header must come late as it is missing includes.
    27 #include "parser.hh"              // for IDENTIFIER, TYPEDEFname, TYPEGENname
     27#include "parser.hh"                                                                    // for IDENTIFIER, TYPEDEFname, TYPEGENname
    2828
    2929using namespace std;
     
    7272// "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the
    7373// name is explicitly used.
    74 void TypedefTable::makeTypedef( const string & name, int kind ) {
     74void TypedefTable::makeTypedef( const string & name, int kind, const char * locn __attribute__((unused)) ) {
    7575//    Check for existence is necessary to handle:
    7676//        struct Fred {};
     
    8080//           Fred();
    8181//        }
     82        debugPrint( cerr << "Make typedef at " << locn << " \"" << name << "\" as " << kindName( kind ) << " scope " << kindTable.currentScope() << endl );
    8283        if ( ! typedefTable.exists( name ) ) {
    8384                typedefTable.addToEnclosingScope( name, kind, "MTD" );
     
    8586} // TypedefTable::makeTypedef
    8687
    87 void TypedefTable::makeTypedef( const string & name ) {
    88         return makeTypedef( name, TYPEDEFname );
     88void TypedefTable::makeTypedef( const string & name, const char * locn __attribute__((unused)) ) {
     89        debugPrint( cerr << "Make typedef at " << locn << " \"" << name << " scope " << kindTable.currentScope() << endl );
     90        return makeTypedef( name, TYPEDEFname, "makeTypede" );
    8991} // TypedefTable::makeTypedef
    9092
    9193void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
    9294        KindTable::size_type scope = kindTable.currentScope();
    93         debugPrint( cerr << "Adding current at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << endl );
     95        debugPrint( cerr << "Adding current at " << locn << " \"" << identifier << "\" as " << kindName( kind ) << " scope " << scope << endl );
    9496        kindTable.insertAt( scope, identifier, kind );
    9597} // TypedefTable::addToScope
     
    98100        KindTable::size_type scope = kindTable.currentScope() - 1 - kindTable.getNote( kindTable.currentScope() - 1 ).level;
    99101//      size_type scope = level - kindTable.getNote( kindTable.currentScope() - 1 ).level;
    100         debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl );
     102        debugPrint( cerr << "Adding enclosing at " << locn << " \"" << identifier << "\" as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl );
    101103        pair< KindTable::iterator, bool > ret = kindTable.insertAt( scope, identifier, kind );
    102104        if ( ! ret.second ) ret.first->second = kind;           // exists => update
  • src/Parser/TypedefTable.h

    r92355883 r2a301ff  
    1010// Created On       : Sat May 16 15:24:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 08:06:37 2020
    13 // Update Count     : 117
     12// Last Modified On : Wed Jul 12 06:09:37 2023
     13// Update Count     : 118
    1414//
    1515
     
    2121
    2222class TypedefTable {
    23         struct Note { size_t level; bool forall; };
     23        struct Note {
     24                size_t level;
     25                bool forall;
     26        };
    2427        typedef ScopedMap< std::string, int, Note > KindTable;
    2528        KindTable kindTable;
     
    3134        bool existsCurr( const std::string & identifier ) const;
    3235        int isKind( const std::string & identifier ) const;
    33         void makeTypedef( const std::string & name, int kind );
    34         void makeTypedef( const std::string & name );
     36        void makeTypedef( const std::string & name, int kind, const char * );
     37        void makeTypedef( const std::string & name, const char * );
    3538        void addToScope( const std::string & identifier, int kind, const char * );
    3639        void addToEnclosingScope( const std::string & identifier, int kind, const char * );
  • src/Parser/parser.yy

    r92355883 r2a301ff  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jun 17 18:53:24 2023
    13 // Update Count     : 6347
     12// Last Modified On : Tue Jul 18 22:51:30 2023
     13// Update Count     : 6391
    1414//
    1515
     
    385385%type<str> string_literal_list
    386386
    387 %type<enum_hiding> hide_opt                                     visible_hide_opt
     387%type<enum_hiding> hide_opt                             visible_hide_opt
    388388
    389389// expressions
    390390%type<expr> constant
    391 %type<expr> tuple                                                       tuple_expression_list
     391%type<expr> tuple                                               tuple_expression_list
    392392%type<oper> ptrref_operator                             unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
    393393%type<expr> primary_expression                  postfix_expression                      unary_expression
    394 %type<expr> cast_expression_list                        cast_expression                         exponential_expression          multiplicative_expression       additive_expression
    395 %type<expr> shift_expression                            relational_expression           equality_expression
     394%type<expr> cast_expression_list                cast_expression                         exponential_expression          multiplicative_expression       additive_expression
     395%type<expr> shift_expression                    relational_expression           equality_expression
    396396%type<expr> AND_expression                              exclusive_OR_expression         inclusive_OR_expression
    397397%type<expr> logical_AND_expression              logical_OR_expression
    398398%type<expr> conditional_expression              constant_expression                     assignment_expression           assignment_expression_opt
    399 %type<expr> comma_expression                            comma_expression_opt
    400 %type<expr> argument_expression_list_opt        argument_expression_list        argument_expression                     default_initializer_opt
     399%type<expr> comma_expression                    comma_expression_opt
     400%type<expr> argument_expression_list_opt argument_expression_list       argument_expression                     default_initializer_opt
    401401%type<ifctl> conditional_declaration
    402 %type<forctl> for_control_expression            for_control_expression_list
     402%type<forctl> for_control_expression    for_control_expression_list
    403403%type<oper> upupeq updown updowneq downupdowneq
    404404%type<expr> subrange
    405405%type<decl> asm_name_opt
    406 %type<expr> asm_operands_opt                            asm_operands_list                       asm_operand
     406%type<expr> asm_operands_opt                    asm_operands_list                       asm_operand
    407407%type<labels> label_list
    408408%type<expr> asm_clobbers_list_opt
     
    412412
    413413// statements
    414 %type<stmt> statement                                           labeled_statement                       compound_statement
     414%type<stmt> statement                                   labeled_statement                       compound_statement
    415415%type<stmt> statement_decl                              statement_decl_list                     statement_list_nodecl
    416416%type<stmt> selection_statement                 if_statement
    417 %type<clause> switch_clause_list_opt            switch_clause_list
     417%type<clause> switch_clause_list_opt    switch_clause_list
    418418%type<expr> case_value
    419 %type<clause> case_clause                               case_value_list                         case_label                                      case_label_list
     419%type<clause> case_clause                               case_value_list                         case_label      case_label_list
    420420%type<stmt> iteration_statement                 jump_statement
    421 %type<stmt> expression_statement                        asm_statement
     421%type<stmt> expression_statement                asm_statement
    422422%type<stmt> with_statement
    423423%type<expr> with_clause_opt
     
    427427%type<stmt> mutex_statement
    428428%type<expr> when_clause                                 when_clause_opt                         waitfor         waituntil               timeout
    429 %type<stmt> waitfor_statement                           waituntil_statement
     429%type<stmt> waitfor_statement                   waituntil_statement
    430430%type<wfs> wor_waitfor_clause
    431431%type<wucn> waituntil_clause                    wand_waituntil_clause       wor_waituntil_clause
     
    601601// around the list separator.
    602602//
    603 //  int f( forall(T) T (*f1) T , forall( S ) S (*f2)( S ) );
     603//  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    604604//      push               pop   push                   pop
    605605
     
    689689        // | RESUME '(' comma_expression ')' compound_statement
    690690        //      { SemanticError( yylloc, "Resume expression is currently unimplemented." ); $$ = nullptr; }
    691         | IDENTIFIER IDENTIFIER                                                         // invalid syntax rules
     691        | IDENTIFIER IDENTIFIER                                                         // invalid syntax rule
    692692                { IdentifierBeforeIdentifier( *$1.str, *$2.str, "n expression" ); $$ = nullptr; }
    693         | IDENTIFIER type_qualifier                                                     // invalid syntax rules
     693        | IDENTIFIER type_qualifier                                                     // invalid syntax rule
    694694                { IdentifierBeforeType( *$1.str, "type qualifier" ); $$ = nullptr; }
    695         | IDENTIFIER storage_class                                                      // invalid syntax rules
     695        | IDENTIFIER storage_class                                                      // invalid syntax rule
    696696                { IdentifierBeforeType( *$1.str, "storage class" ); $$ = nullptr; }
    697         | IDENTIFIER basic_type_name                                            // invalid syntax rules
     697        | IDENTIFIER basic_type_name                                            // invalid syntax rule
    698698                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    699         | IDENTIFIER TYPEDEFname                                                        // invalid syntax rules
     699        | IDENTIFIER TYPEDEFname                                                        // invalid syntax rule
    700700                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    701         | IDENTIFIER TYPEGENname                                                        // invalid syntax rules
     701        | IDENTIFIER TYPEGENname                                                        // invalid syntax rule
    702702                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    703703        ;
     
    12751275        | DEFAULT ':'                                                           { $$ = new ClauseNode( build_default( yylloc ) ); }
    12761276                // A semantic check is required to ensure only one default clause per switch/choose statement.
    1277         | DEFAULT error                                                                         //  invalid syntax rules
     1277        | DEFAULT error                                                                         //  invalid syntax rule
    12781278                { SemanticError( yylloc, "syntax error, colon missing after default." ); $$ = nullptr; }
    12791279        ;
     
    14051405                        else { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
    14061406                }
    1407         | comma_expression updowneq comma_expression '~' '@' // CFA, invalid syntax rules
     1407        | comma_expression updowneq comma_expression '~' '@' // CFA, invalid syntax rule
    14081408                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    1409         | '@' updowneq '@'                                                                      // CFA, invalid syntax rules
     1409        | '@' updowneq '@'                                                                      // CFA, invalid syntax rule
    14101410                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    1411         | '@' updowneq comma_expression '~' '@'                         // CFA, invalid syntax rules
     1411        | '@' updowneq comma_expression '~' '@'                         // CFA, invalid syntax rule
    14121412                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    1413         | comma_expression updowneq '@' '~' '@'                         // CFA, invalid syntax rules
     1413        | comma_expression updowneq '@' '~' '@'                         // CFA, invalid syntax rule
    14141414                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    1415         | '@' updowneq '@' '~' '@'                                                      // CFA, invalid syntax rules
     1415        | '@' updowneq '@' '~' '@'                                                      // CFA, invalid syntax rule
    14161416                { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
    14171417
     
    14341434                        else $$ = forCtrl( yylloc, $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
    14351435                }
    1436         | comma_expression ';' '@' updowneq '@'                         // CFA, invalid syntax rules
     1436        | comma_expression ';' '@' updowneq '@'                         // CFA, invalid syntax rule
    14371437                { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
    14381438
    14391439        | comma_expression ';' comma_expression updowneq comma_expression '~' comma_expression // CFA
    14401440                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
    1441         | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, invalid syntax rules
     1441        | comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, invalid syntax rule
    14421442                {
    14431443                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
     
    14521452        | comma_expression ';' comma_expression updowneq comma_expression '~' '@' // CFA
    14531453                { $$ = forCtrl( yylloc, $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
    1454         | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rules
     1454        | comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, invalid syntax rule
    14551455                {
    14561456                        if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
     
    15111511                        else $$ = forCtrl( yylloc, $1, $2, $3, nullptr, nullptr );
    15121512                }
    1513         | declaration '@' updowneq '@' '~' '@'                          // CFA, invalid syntax rules
     1513        | declaration '@' updowneq '@' '~' '@'                          // CFA, invalid syntax rule
    15141514                { SemanticError( yylloc, "syntax error, missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
    15151515
     
    16661666                { $$ = build_waitfor_timeout( yylloc, $1, $3, $4, maybe_build_compound( yylloc, $5 ) ); }
    16671667        // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    1668         | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rules
     1668        | wor_waitfor_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rule
    16691669                { SemanticError( yylloc, "syntax error, else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    16701670        | wor_waitfor_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
     
    17081708        | wor_waituntil_clause wor when_clause_opt ELSE statement
    17091709                { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_else( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
    1710         | wor_waituntil_clause wor when_clause_opt timeout statement    %prec THEN
    1711                 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ) ); }
    1712         // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    1713         | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // invalid syntax rules
    1714                 { SemanticError( yylloc, "syntax error, else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    1715         | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
    1716                 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1,
    1717                 new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR,
    1718                     build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ),
    1719                     build_waituntil_else( yylloc, $7, maybe_build_compound( yylloc, $9 ) ) ) ); }
    17201710        ;
    17211711
    17221712waituntil_statement:
    17231713        wor_waituntil_clause                                                            %prec THEN
    1724                 // SKULLDUGGERY: create an empty compound statement to test parsing of waituntil statement.
    1725                 {
    1726             $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) );
    1727             // $$ = new StatementNode( build_compound( yylloc, nullptr ) );
    1728         }
     1714                { $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) ); }
    17291715        ;
    17301716
     
    18681854
    18691855KR_parameter_list:
    1870         push c_declaration pop ';'
    1871                 { $$ = $2; }
    1872         | KR_parameter_list push c_declaration pop ';'
    1873                 { $$ = $1->appendList( $3 ); }
     1856        c_declaration ';'
     1857                { $$ = $1; }
     1858        | KR_parameter_list c_declaration ';'
     1859                { $$ = $1->appendList( $2 ); }
    18741860        ;
    18751861
     
    20071993        TYPEDEF cfa_variable_specifier
    20081994                {
    2009                         typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, "1" );
     1995                        typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, "cfa_typedef_declaration 1" );
    20101996                        $$ = $2->addTypedef();
    20111997                }
    20121998        | TYPEDEF cfa_function_specifier
    20131999                {
    2014                         typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, "2" );
     2000                        typedefTable.addToEnclosingScope( *$2->name, TYPEDEFname, "cfa_typedef_declaration 2" );
    20152001                        $$ = $2->addTypedef();
    20162002                }
    20172003        | cfa_typedef_declaration pop ',' push identifier
    20182004                {
    2019                         typedefTable.addToEnclosingScope( *$5, TYPEDEFname, "3" );
     2005                        typedefTable.addToEnclosingScope( *$5, TYPEDEFname, "cfa_typedef_declaration 3" );
    20202006                        $$ = $1->appendList( $1->cloneType( $5 ) );
    20212007                }
     
    20282014        TYPEDEF type_specifier declarator
    20292015                {
    2030                         typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "4" );
     2016                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "typedef_declaration 1" );
    20312017                        if ( $2->type->forall || ($2->type->kind == TypeData::Aggregate && $2->type->aggregate.params) ) {
    20322018                                SemanticError( yylloc, "forall qualifier in typedef is currently unimplemented." ); $$ = nullptr;
    20332019                        } else $$ = $3->addType( $2 )->addTypedef(); // watchout frees $2 and $3
    20342020                }
    2035         | typedef_declaration pop ',' push declarator
    2036                 {
    2037                         typedefTable.addToEnclosingScope( *$5->name, TYPEDEFname, "5" );
    2038                         $$ = $1->appendList( $1->cloneBaseType( $5 )->addTypedef() );
     2021        | typedef_declaration ',' declarator
     2022                {
     2023                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "typedef_declaration 2" );
     2024                        $$ = $1->appendList( $1->cloneBaseType( $3 )->addTypedef() );
    20392025                }
    20402026        | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 )
     
    20522038                        SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    20532039                }
    2054         | typedef_expression pop ',' push identifier '=' assignment_expression
     2040        | typedef_expression ',' identifier '=' assignment_expression
    20552041                {
    20562042                        SemanticError( yylloc, "TYPEDEF expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     
    24652451        | aggregate_key attribute_list_opt identifier
    24662452                {
    2467                         typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
     2453                        typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname, "aggregate_type: 1" );
    24682454                        forall = false;                                                         // reset
    24692455                }
     
    24742460        | aggregate_key attribute_list_opt TYPEDEFname          // unqualified type name
    24752461                {
    2476                         typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
     2462                        typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname, "aggregate_type: 2" );
    24772463                        forall = false;                                                         // reset
    24782464                }
     
    24842470        | aggregate_key attribute_list_opt TYPEGENname          // unqualified type name
    24852471                {
    2486                         typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
     2472                        typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname, "aggregate_type: 3" );
    24872473                        forall = false;                                                         // reset
    24882474                }
     
    25052491        aggregate_key attribute_list_opt identifier
    25062492                {
    2507                         typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname );
     2493                        typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname, "aggregate_type_nobody" );
    25082494                        forall = false;                                                         // reset
    25092495                        $$ = DeclarationNode::newAggregate( $1, $3, nullptr, nullptr, false )->addQualifiers( $2 );
     
    26802666        ENUM attribute_list_opt '{' enumerator_list comma_opt '}'
    26812667                { $$ = DeclarationNode::newEnum( nullptr, $4, true, false )->addQualifiers( $2 ); }
     2668        | ENUM attribute_list_opt '!' '{' enumerator_list comma_opt '}' // invalid syntax rule
     2669                { SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
    26822670        | ENUM attribute_list_opt identifier
    2683                 { typedefTable.makeTypedef( *$3 ); }
     2671                { typedefTable.makeTypedef( *$3, "enum_type 1" ); }
    26842672          hide_opt '{' enumerator_list comma_opt '}'
    26852673                { $$ = DeclarationNode::newEnum( $3, $7, true, false, nullptr, $5 )->addQualifiers( $2 ); }
    2686         | ENUM attribute_list_opt typedef_name                          // unqualified type name
    2687           hide_opt '{' enumerator_list comma_opt '}'
     2674        | ENUM attribute_list_opt typedef_name hide_opt '{' enumerator_list comma_opt '}' // unqualified type name
    26882675                { $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); }
    26892676        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
     
    26942681                        $$ = DeclarationNode::newEnum( nullptr, $7, true, true, $3 )->addQualifiers( $5 );
    26952682                }
     2683        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}' // unqualified type name
     2684                { SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
     2685        | ENUM '(' ')' attribute_list_opt '{' enumerator_list comma_opt '}'
     2686                {
     2687                        $$ = DeclarationNode::newEnum( nullptr, $6, true, true )->addQualifiers( $4 );
     2688                }
     2689        | ENUM '(' ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}' // invalid syntax rule
     2690                { SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
    26962691        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    26972692                {
     
    26992694                                SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
    27002695                        }
    2701                         typedefTable.makeTypedef( *$6 );
     2696                        typedefTable.makeTypedef( *$6, "enum_type 2" );
    27022697                }
    27032698          hide_opt '{' enumerator_list comma_opt '}'
     
    27052700                        $$ = DeclarationNode::newEnum( $6, $11, true, true, $3, $9 )->addQualifiers( $5 )->addQualifiers( $7 );
    27062701                }
    2707         | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt
    2708           hide_opt '{' enumerator_list comma_opt '}'
     2702        | ENUM '(' ')' attribute_list_opt identifier attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
     2703                {
     2704                        $$ = DeclarationNode::newEnum( $5, $9, true, true, nullptr, $7 )->addQualifiers( $4 )->addQualifiers( $6 );
     2705                }
     2706        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
    27092707                {
    27102708                        $$ = DeclarationNode::newEnum( $6->name, $10, true, true, $3, $8 )->addQualifiers( $5 )->addQualifiers( $7 );
     2709                }
     2710        | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
     2711                {
     2712                        $$ = DeclarationNode::newEnum( $5->name, $9, true, true, nullptr, $7 )->addQualifiers( $4 )->addQualifiers( $6 );
    27112713                }
    27122714        | enum_type_nobody
     
    27222724enum_type_nobody:                                                                               // enum - {...}
    27232725        ENUM attribute_list_opt identifier
    2724                 { typedefTable.makeTypedef( *$3 ); $$ = DeclarationNode::newEnum( $3, nullptr, false, false )->addQualifiers( $2 ); }
     2726                {
     2727                        typedefTable.makeTypedef( *$3, "enum_type_nobody 1" );
     2728                        $$ = DeclarationNode::newEnum( $3, nullptr, false, false )->addQualifiers( $2 );
     2729                }
    27252730        | ENUM attribute_list_opt type_name
    2726                 { typedefTable.makeTypedef( *$3->type->symbolic.name ); $$ = DeclarationNode::newEnum( $3->type->symbolic.name, nullptr, false, false )->addQualifiers( $2 ); }
     2731                {
     2732                        typedefTable.makeTypedef( *$3->type->symbolic.name, "enum_type_nobody 2" );
     2733                        $$ = DeclarationNode::newEnum( $3->type->symbolic.name, nullptr, false, false )->addQualifiers( $2 );
     2734                }
    27272735        ;
    27282736
     
    27922800                { $$ = nullptr; }
    27932801        | parameter_list
    2794         | parameter_list pop ',' push ELLIPSIS
     2802        | parameter_list ',' ELLIPSIS
    27952803                { $$ = $1->addVarArgs(); }
    27962804        ;
     
    27992807        abstract_parameter_declaration
    28002808        | parameter_declaration
    2801         | parameter_list pop ',' push abstract_parameter_declaration
    2802                 { $$ = $1->appendList( $5 ); }
    2803         | parameter_list pop ',' push parameter_declaration
    2804                 { $$ = $1->appendList( $5 ); }
     2809        | parameter_list ',' abstract_parameter_declaration
     2810                { $$ = $1->appendList( $3 ); }
     2811        | parameter_list ',' parameter_declaration
     2812                { $$ = $1->appendList( $3 ); }
    28052813        ;
    28062814
     
    29692977        type_class identifier_or_type_name
    29702978                {
    2971                         typedefTable.addToScope( *$2, TYPEDEFname, "9" );
     2979                        typedefTable.addToScope( *$2, TYPEDEFname, "type_parameter 1" );
    29722980                        if ( $1 == ast::TypeDecl::Otype ) { SemanticError( yylloc, "otype keyword is deprecated, use T " ); }
    29732981                        if ( $1 == ast::TypeDecl::Dtype ) { SemanticError( yylloc, "dtype keyword is deprecated, use T &" ); }
     
    29772985                { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); }
    29782986        | identifier_or_type_name new_type_class
    2979                 { typedefTable.addToScope( *$1, TYPEDEFname, "9" ); }
     2987                { typedefTable.addToScope( *$1, TYPEDEFname, "type_parameter 2" ); }
    29802988          type_initializer_opt assertion_list_opt
    29812989                { $$ = DeclarationNode::newTypeParam( $2, $1 )->addTypeInitializer( $4 )->addAssertions( $5 ); }
    29822990        | '[' identifier_or_type_name ']'
    29832991                {
    2984                         typedefTable.addToScope( *$2, TYPEDIMname, "9" );
     2992                        typedefTable.addToScope( *$2, TYPEDIMname, "type_parameter 3" );
    29852993                        $$ = DeclarationNode::newTypeParam( ast::TypeDecl::Dimension, $2 );
    29862994                }
     
    30643072        identifier_or_type_name
    30653073                {
    3066                         typedefTable.addToEnclosingScope( *$1, TYPEDEFname, "10" );
     3074                        typedefTable.addToEnclosingScope( *$1, TYPEDEFname, "type_declarator_name 1" );
    30673075                        $$ = DeclarationNode::newTypeDecl( $1, nullptr );
    30683076                }
    30693077        | identifier_or_type_name '(' type_parameter_list ')'
    30703078                {
    3071                         typedefTable.addToEnclosingScope( *$1, TYPEGENname, "11" );
     3079                        typedefTable.addToEnclosingScope( *$1, TYPEGENname, "type_declarator_name 2" );
    30723080                        $$ = DeclarationNode::newTypeDecl( $1, $3 );
    30733081                }
     
    31633171        | IDENTIFIER IDENTIFIER
    31643172                { IdentifierBeforeIdentifier( *$1.str, *$2.str, " declaration" ); $$ = nullptr; }
    3165         | IDENTIFIER type_qualifier                                                     // invalid syntax rules
     3173        | IDENTIFIER type_qualifier                                                     // invalid syntax rule
    31663174                { IdentifierBeforeType( *$1.str, "type qualifier" ); $$ = nullptr; }
    3167         | IDENTIFIER storage_class                                                      // invalid syntax rules
     3175        | IDENTIFIER storage_class                                                      // invalid syntax rule
    31683176                { IdentifierBeforeType( *$1.str, "storage class" ); $$ = nullptr; }
    3169         | IDENTIFIER basic_type_name                                            // invalid syntax rules
     3177        | IDENTIFIER basic_type_name                                            // invalid syntax rule
    31703178                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    3171         | IDENTIFIER TYPEDEFname                                                        // invalid syntax rules
     3179        | IDENTIFIER TYPEDEFname                                                        // invalid syntax rule
    31723180                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    3173         | IDENTIFIER TYPEGENname                                                        // invalid syntax rules
     3181        | IDENTIFIER TYPEGENname                                                        // invalid syntax rule
    31743182                { IdentifierBeforeType( *$1.str, "type" ); $$ = nullptr; }
    31753183        | external_function_definition
     
    34583466
    34593467variable_function:
    3460         '(' variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3461                 { $$ = $2->addParamList( $6 ); }
    3462         | '(' attribute_list variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3463                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
     3468        '(' variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3469                { $$ = $2->addParamList( $5 ); }
     3470        | '(' attribute_list variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3471                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    34643472        | '(' variable_function ')'                                                     // redundant parenthesis
    34653473                { $$ = $2; }
     
    34813489
    34823490function_no_ptr:
    3483         paren_identifier '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3484                 { $$ = $1->addParamList( $4 ); }
    3485         | '(' function_ptr ')' '(' push parameter_type_list_opt pop ')'
    3486                 { $$ = $2->addParamList( $6 ); }
    3487         | '(' attribute_list function_ptr ')' '(' push parameter_type_list_opt pop ')'
    3488                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
     3491        paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3492                { $$ = $1->addParamList( $3 ); }
     3493        | '(' function_ptr ')' '(' parameter_type_list_opt ')'
     3494                { $$ = $2->addParamList( $5 ); }
     3495        | '(' attribute_list function_ptr ')' '(' parameter_type_list_opt ')'
     3496                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    34893497        | '(' function_no_ptr ')'                                                       // redundant parenthesis
    34903498                { $$ = $2; }
     
    35353543        paren_identifier '(' identifier_list ')'                        // function_declarator handles empty parameter
    35363544                { $$ = $1->addIdList( $3 ); }
    3537         | '(' KR_function_ptr ')' '(' push parameter_type_list_opt pop ')'
    3538                 { $$ = $2->addParamList( $6 ); }
    3539         | '(' attribute_list KR_function_ptr ')' '(' push parameter_type_list_opt pop ')'
    3540                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
     3545        | '(' KR_function_ptr ')' '(' parameter_type_list_opt ')'
     3546                { $$ = $2->addParamList( $5 ); }
     3547        | '(' attribute_list KR_function_ptr ')' '(' parameter_type_list_opt ')'
     3548                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    35413549        | '(' KR_function_no_ptr ')'                                            // redundant parenthesis
    35423550                { $$ = $2; }
     
    35823590                {
    35833591                        // hide type name in enclosing scope by variable name
    3584                         typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" );
     3592                        typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "paren_type" );
    35853593                }
    35863594        | '(' paren_type ')'
     
    36273635
    36283636variable_type_function:
    3629         '(' variable_type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3630                 { $$ = $2->addParamList( $6 ); }
    3631         | '(' attribute_list variable_type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3632                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
     3637        '(' variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3638                { $$ = $2->addParamList( $5 ); }
     3639        | '(' attribute_list variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3640                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    36333641        | '(' variable_type_function ')'                                        // redundant parenthesis
    36343642                { $$ = $2; }
     
    36503658
    36513659function_type_no_ptr:
    3652         paren_type '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3653                 { $$ = $1->addParamList( $4 ); }
    3654         | '(' function_type_ptr ')' '(' push parameter_type_list_opt pop ')'
    3655                 { $$ = $2->addParamList( $6 ); }
    3656         | '(' attribute_list function_type_ptr ')' '(' push parameter_type_list_opt pop ')'
    3657                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
     3660        paren_type '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3661                { $$ = $1->addParamList( $3 ); }
     3662        | '(' function_type_ptr ')' '(' parameter_type_list_opt ')'
     3663                { $$ = $2->addParamList( $5 ); }
     3664        | '(' attribute_list function_type_ptr ')' '(' parameter_type_list_opt ')'
     3665                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    36583666        | '(' function_type_no_ptr ')'                                          // redundant parenthesis
    36593667                { $$ = $2; }
     
    37263734
    37273735identifier_parameter_function:
    3728         paren_identifier '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3729                 { $$ = $1->addParamList( $4 ); }
    3730         | '(' identifier_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3731                 { $$ = $2->addParamList( $6 ); }
     3736        paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3737                { $$ = $1->addParamList( $3 ); }
     3738        | '(' identifier_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3739                { $$ = $2->addParamList( $5 ); }
    37323740        | '(' identifier_parameter_function ')'                         // redundant parenthesis
    37333741                { $$ = $2; }
     
    37793787
    37803788type_parameter_function:
    3781         typedef_name '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3782                 { $$ = $1->addParamList( $4 ); }
    3783         | '(' type_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3784                 { $$ = $2->addParamList( $6 ); }
     3789        typedef_name '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3790                { $$ = $1->addParamList( $3 ); }
     3791        | '(' type_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3792                { $$ = $2->addParamList( $5 ); }
    37853793        ;
    37863794
     
    38293837
    38303838abstract_function:
    3831         '(' push parameter_type_list_opt pop ')'                        // empty parameter list OBSOLESCENT (see 3)
    3832                 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $3, nullptr ); }
    3833         | '(' abstract_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3834                 { $$ = $2->addParamList( $6 ); }
     3839        '(' parameter_type_list_opt ')'                 // empty parameter list OBSOLESCENT (see 3)
     3840                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
     3841        | '(' abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3842                { $$ = $2->addParamList( $5 ); }
    38353843        | '(' abstract_function ')'                                                     // redundant parenthesis
    38363844                { $$ = $2; }
     
    39523960
    39533961abstract_parameter_function:
    3954         '(' push parameter_type_list_opt pop ')'                        // empty parameter list OBSOLESCENT (see 3)
    3955                 { $$ = DeclarationNode::newFunction( nullptr, nullptr, $3, nullptr ); }
    3956         | '(' abstract_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3957                 { $$ = $2->addParamList( $6 ); }
     3962        '(' parameter_type_list_opt ')'                 // empty parameter list OBSOLESCENT (see 3)
     3963                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
     3964        | '(' abstract_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3965                { $$ = $2->addParamList( $5 ); }
    39583966        | '(' abstract_parameter_function ')'                           // redundant parenthesis
    39593967                { $$ = $2; }
     
    39924000// This pattern parses a declaration of an abstract variable, but does not allow "int ()" for a function pointer.
    39934001//
    3994 //              struct S {
    3995 //          int;
    3996 //          int *;
    3997 //          int [10];
    3998 //          int (*)();
    3999 //      };
     4002//   struct S {
     4003//       int;
     4004//       int *;
     4005//       int [10];
     4006//       int (*)();
     4007//   };
    40004008
    40014009variable_abstract_declarator:
     
    40314039
    40324040variable_abstract_function:
    4033         '(' variable_abstract_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    4034                 { $$ = $2->addParamList( $6 ); }
     4041        '(' variable_abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     4042                { $$ = $2->addParamList( $5 ); }
    40354043        | '(' variable_abstract_function ')'                            // redundant parenthesis
    40364044                { $$ = $2; }
  • src/ResolvExpr/CommonType.cc

    r92355883 r2a301ff  
    696696                void postvisit( const ast::BasicType * basic ) {
    697697                        if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
    698                                 #warning remove casts when `commonTypes` moved to new AST
    699                                
    700                                 /*
    701                                 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
    702                                 if (
    703                                         ( ( kind == basic->kind && basic->qualifiers >= basic2->qualifiers )
    704                                                 || widen.first )
    705                                         && ( ( kind == basic2->kind && basic->qualifiers <= basic2->qualifiers )
    706                                                 || widen.second )
    707                                 ) {
    708                                         result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
    709                                 }
    710                                 */
    711698                                ast::BasicType::Kind kind;
    712699                                if (basic->kind != basic2->kind && !widen.first && !widen.second) return;
     
    719706                                        result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
    720707                                }
    721                                
    722708                        } else if (
    723709                                dynamic_cast< const ast::ZeroType * >( type2 )
    724710                                || dynamic_cast< const ast::OneType * >( type2 )
    725711                        ) {
    726                                 #warning remove casts when `commonTypes` moved to new AST
    727                                 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
    728                                 /*
    729                                 if ( // xxx - what does qualifier even do here??
    730                                         ( ( basic->qualifiers >= type2->qualifiers )
    731                                                 || widen.first )
    732                                          && ( ( /* kind != basic->kind && basic->qualifiers <= type2->qualifiers )
    733                                                 || widen.second )
    734                                 )
    735                                 */
    736712                                if (widen.second) {
    737713                                        result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers };
    738714                                }
    739715                        } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
    740                                 #warning remove casts when `commonTypes` moved to new AST
    741716                                const ast::EnumDecl* enumDecl = enumInst->base;
    742717                                if ( enumDecl->base ) {
    743718                                        result = enumDecl->base.get();
    744719                                } else {
     720                                        #warning remove casts when `commonTypes` moved to new AST
    745721                                        ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
    746722                                        if (
     
    763739                                auto entry = open.find( *var );
    764740                                if ( entry != open.end() ) {
    765                                 // if (tenv.lookup(*var)) {
    766741                                        ast::AssertionSet need, have;
    767742                                        if ( ! tenv.bindVar(
  • src/ResolvExpr/ResolveTypeof.h

    r92355883 r2a301ff  
    3030        Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
    3131        const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
     32        const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
    3233        const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
    3334        const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext &);
  • src/ResolvExpr/Unify.cc

    r92355883 r2a301ff  
    3232#include "AST/Type.hpp"
    3333#include "AST/TypeEnvironment.hpp"
     34#include "Common/Eval.h"            // for eval
    3435#include "Common/PassVisitor.h"     // for PassVisitor
    3536#include "CommonType.hpp"           // for commonType
     
    779780        }
    780781
     782        // Unification of Expressions
     783        //
     784        // Boolean outcome (obvious):  Are they basically spelled the same?
     785        // Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
     786        //
     787        // Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
     788        // where the VAREXPR are meant as notational metavariables representing the fact that unification always
     789        // sees distinct ast::VariableExpr objects at these positions
     790
     791        static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
     792                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     793                WidenMode widen );
     794
     795        class UnifyExpr final : public ast::WithShortCircuiting {
     796                const ast::Expr * e2;
     797                ast::TypeEnvironment & tenv;
     798                ast::AssertionSet & need;
     799                ast::AssertionSet & have;
     800                const ast::OpenVarSet & open;
     801                WidenMode widen;
     802        public:
     803                bool result;
     804
     805        private:
     806
     807                void tryMatchOnStaticValue( const ast::Expr * e1 ) {
     808                        Evaluation r1 = eval(e1);
     809                        Evaluation r2 = eval(e2);
     810
     811                        if ( ! r1.hasKnownValue ) return;
     812                        if ( ! r2.hasKnownValue ) return;
     813
     814                        if (r1.knownValue != r2.knownValue) return;
     815
     816                        visit_children = false;
     817                        result = true;
     818                }
     819
     820        public:
     821
     822                void previsit( const ast::Node * ) { assert(false); }
     823
     824                void previsit( const ast::Expr * e1 ) {
     825                        tryMatchOnStaticValue( e1 );
     826                        visit_children = false;
     827                }
     828
     829                void previsit( const ast::CastExpr * e1 ) {
     830                        tryMatchOnStaticValue( e1 );
     831
     832                        if (result) {
     833                                assert (visit_children == false);
     834                        } else {
     835                                assert (visit_children == true);
     836                                visit_children = false;
     837
     838                                auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
     839                                if ( ! e2c ) return;
     840
     841                                // inspect casts' target types
     842                                if ( ! unifyExact(
     843                                        e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
     844
     845                                // inspect casts' inner expressions
     846                                result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
     847                        }
     848                }
     849
     850                void previsit( const ast::VariableExpr * e1 ) {
     851                        tryMatchOnStaticValue( e1 );
     852
     853                        if (result) {
     854                                assert (visit_children == false);
     855                        } else {
     856                                assert (visit_children == true);
     857                                visit_children = false;
     858
     859                                auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
     860                                if ( ! e2v ) return;
     861
     862                                assert(e1->var);
     863                                assert(e2v->var);
     864
     865                                // conservative: variable exprs match if their declarations are represented by the same C++ AST object
     866                                result = (e1->var == e2v->var);
     867                        }
     868                }
     869
     870                void previsit( const ast::SizeofExpr * e1 ) {
     871                        tryMatchOnStaticValue( e1 );
     872
     873                        if (result) {
     874                                assert (visit_children == false);
     875                        } else {
     876                                assert (visit_children == true);
     877                                visit_children = false;
     878
     879                                auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
     880                                if ( ! e2so ) return;
     881
     882                                assert((e1->type != nullptr) ^ (e1->expr != nullptr));
     883                                assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
     884                                if ( ! (e1->type && e2so->type) )  return;
     885
     886                                // expression unification calls type unification (mutual recursion)
     887                                result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
     888                        }
     889                }
     890
     891                UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
     892                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
     893                : e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
     894        };
     895
     896        static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
     897                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     898                WidenMode widen ) {
     899                assert( e1 && e2 );
     900                return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
     901        }
     902
    781903        class Unify_new final : public ast::WithShortCircuiting {
    782904                const ast::Type * type2;
     
    820942                        if ( ! array2 ) return;
    821943
    822                         // to unify, array types must both be VLA or both not VLA and both must have a
    823                         // dimension expression or not have a dimension
    824944                        if ( array->isVarLen != array2->isVarLen ) return;
    825                         if ( ! array->isVarLen && ! array2->isVarLen
    826                                         && array->dimension && array2->dimension ) {
    827                                 auto ce1 = array->dimension.as< ast::ConstantExpr >();
    828                                 auto ce2 = array2->dimension.as< ast::ConstantExpr >();
    829 
    830                                 // see C11 Reference Manual 6.7.6.2.6
    831                                 // two array types with size specifiers that are integer constant expressions are
    832                                 // compatible if both size specifiers have the same constant value
    833                                 if ( ce1 && ce2 && ce1->intValue() != ce2->intValue() ) return;
     945                        if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
     946
     947                        if ( array->dimension ) {
     948                                assert( array2->dimension );
     949                                // type unification calls expression unification (mutual recursion)
     950                                if ( ! unify(array->dimension, array2->dimension,
     951                                    tenv, need, have, open, widen) ) return;
    834952                        }
    835953
     
    11801298                auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
    11811299                auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
    1182                 ast::OpenVarSet::const_iterator
    1183                         entry1 = var1 ? open.find( *var1 ) : open.end(),
    1184                         entry2 = var2 ? open.find( *var2 ) : open.end();
    1185                 // bool isopen1 = entry1 != open.end();
    1186                 // bool isopen2 = entry2 != open.end();
    11871300                bool isopen1 = var1 && env.lookup(*var1);
    11881301                bool isopen2 = var2 && env.lookup(*var2);
    11891302
    1190                 /*
    1191                 if ( isopen1 && isopen2 ) {
    1192                         if ( entry1->second.kind != entry2->second.kind ) return false;
    1193                         return env.bindVarToVar(
    1194                                 var1, var2, ast::TypeData{ entry1->second, entry2->second }, need, have,
    1195                                 open, widen );
    1196                 } else if ( isopen1 ) {
    1197                         return env.bindVar( var1, type2, entry1->second, need, have, open, widen );
    1198                 } else if ( isopen2 ) {
    1199                         return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );
    1200                 } */
    12011303                if ( isopen1 && isopen2 ) {
    12021304                        if ( var1->base->kind != var2->base->kind ) return false;
     
    12081310                } else if ( isopen2 ) {
    12091311                        return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
    1210                 }else {
     1312                } else {
    12111313                        return ast::Pass<Unify_new>::read(
    12121314                                type1, type2, env, need, have, open, widen );
    12131315                }
    1214                
    12151316        }
    12161317
  • src/SymTab/FixFunction.cc

    r92355883 r2a301ff  
    109109
    110110                const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
    111                         return new ast::ObjectDecl{
    112                                 func->location, func->name, new ast::PointerType{ func->type }, nullptr,
     111                        // Cannot handle cases with asserions.
     112                        assert( func->assertions.empty() );
     113                        return new ast::ObjectDecl{
     114                                func->location, func->name, new ast::PointerType( func->type ), nullptr,
    113115                                func->storage, func->linkage, nullptr, copy( func->attributes ) };
    114116                }
     
    117119
    118120                const ast::Type * postvisit( const ast::ArrayType * array ) {
    119                         return new ast::PointerType{ 
    120                                 array->base, array->dimension, array->isVarLen, array->isStatic, 
     121                        return new ast::PointerType{
     122                                array->base, array->dimension, array->isVarLen, array->isStatic,
    121123                                array->qualifiers };
    122124                }
  • src/SymTab/GenImplicitCall.cpp

    r92355883 r2a301ff  
    1616#include "GenImplicitCall.hpp"
    1717
     18#include "AST/Copy.hpp"                  // for deepCopy
    1819#include "AST/Decl.hpp"                  // for ObjectDecl
    1920#include "AST/Expr.hpp"                  // for ConstantExpr, UntypedExpr,...
     
    115116        std::string cmp, update;
    116117
     118        const ast::Expr * dimension = deepCopy( array->dimension );
    117119        if ( forward ) {
    118120                // generate: for ( int i = 0; i < N; ++i )
    119121                begin = ast::ConstantExpr::from_int( loc, 0 );
    120                 end = array->dimension;
     122                end = dimension;
    121123                cmp = "?<?";
    122124                update = "++?";
     
    124126                // generate: for ( int i = N-1; i >= 0; --i )
    125127                begin = ast::UntypedExpr::createCall( loc, "?-?",
    126                         { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
     128                        { dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
    127129                end = ast::ConstantExpr::from_int( loc, 0 );
    128130                cmp = "?>=?";
  • src/Validate/Autogen.cpp

    r92355883 r2a301ff  
    532532                )
    533533        );
    534         return genImplicitCall(
     534        auto stmt = genImplicitCall(
    535535                srcParam, dstSelect, location, func->name,
    536536                field, direction
    537537        );
     538        // This could return the above directly, except the generated code is
     539        // built using the structure's members and that means all the scoped
     540        // names (the forall parameters) are incorrect. This corrects them.
     541        if ( stmt && !decl->params.empty() ) {
     542                ast::DeclReplacer::TypeMap oldToNew;
     543                for ( auto pair : group_iterate( decl->params, func->type_params ) ) {
     544                        oldToNew.emplace( std::get<0>(pair), std::get<1>(pair) );
     545                }
     546                auto node = ast::DeclReplacer::replace( stmt, oldToNew );
     547                stmt = strict_dynamic_cast<const ast::Stmt *>( node );
     548        }
     549        return stmt;
    538550}
    539551
  • src/Validate/FixQualifiedTypes.cpp

    r92355883 r2a301ff  
    8989        }
    9090
    91         ast::Expr const * postvisit( ast::QualifiedNameExpr const * t) {
     91        ast::Expr const * postvisit( ast::QualifiedNameExpr const * t ) {
    9292                assert( location );
    93                 if ( t->type_decl ) {
    94                 auto enumName = t->type_decl->name;
    95                 const ast::EnumDecl * enumDecl = symtab.lookupEnum( enumName );
    96                         for ( ast::ptr<ast::Decl> const & member : enumDecl->members ) {
    97                                 if ( auto memberAsObj = member.as<ast::ObjectDecl>() ) {
    98                                         if ( memberAsObj->name == t->name ) {
    99                                                 return new ast::VariableExpr( t->location, memberAsObj );
    100                                         }
    101                                 } else {
    102                                         assertf( false, "unhandled qualified child type");
     93                if ( !t->type_decl ) return t;
     94
     95                auto enumName = t->type_decl->name;
     96                const ast::EnumDecl * enumDecl = symtab.lookupEnum( enumName );
     97                for ( ast::ptr<ast::Decl> const & member : enumDecl->members ) {
     98                        if ( auto memberAsObj = member.as<ast::ObjectDecl>() ) {
     99                                if ( memberAsObj->name == t->name ) {
     100                                        return new ast::VariableExpr( t->location, memberAsObj );
    103101                                }
     102                        } else {
     103                                assertf( false, "unhandled qualified child type" );
    104104                        }
     105                }
    105106
    106                 auto var = new ast::ObjectDecl( t->location, t->name,
    107                         new ast::EnumInstType(enumDecl, ast::CV::Const), nullptr, {}, ast::Linkage::Cforall );
    108                         var->mangleName = Mangle::mangle( var );
    109                         return new ast::VariableExpr( t->location, var );
    110         }
    111 
    112                 return t;
     107                auto var = new ast::ObjectDecl( t->location, t->name,
     108                        new ast::EnumInstType( enumDecl, ast::CV::Const ),
     109                        nullptr, {}, ast::Linkage::Cforall );
     110                var->mangleName = Mangle::mangle( var );
     111                return new ast::VariableExpr( t->location, var );
    113112        }
    114113
  • src/Validate/ForallPointerDecay.cpp

    r92355883 r2a301ff  
    2323#include "Common/CodeLocation.h"
    2424#include "Common/ToString.hpp"
     25#include "Common/utility.h"
    2526#include "SymTab/FixFunction.h"
    26 
    27 #include "AST/Print.hpp"
    2827
    2928namespace Validate {
     
    5150}
    5251
    53 template<typename T>
    54 void append( std::vector<T> & dst, std::vector<T> & src ) {
    55         dst.reserve( dst.size() + src.size() );
    56         for ( auto el : src ) {
    57                 dst.emplace_back( std::move( el ) );
    58         }
    59         src.clear();
     52ast::FunctionDecl * updateAssertions( ast::FunctionDecl * decl ) {
     53        auto type = ast::mutate( decl->type.get() );
     54        type->assertions.clear();
     55        type->assertions.reserve( decl->assertions.size() );
     56        for ( auto & assertion : decl->assertions ) {
     57                type->assertions.emplace_back(
     58                        new ast::VariableExpr( decl->location, assertion ) );
     59        }
     60        decl->type = type;
     61        return decl;
    6062}
    6163
     
    9698                                        decl->get_type() ) ) {
    9799                                auto moreAsserts = expandTrait( traitInst );
    98                                 append( assertions, moreAsserts );
     100                                splice( assertions, moreAsserts );
    99101                        } else {
    100102                                assertions.push_back( decl );
     
    108110        static TypeDeclVec expandTypeDecls( const TypeDeclVec & old ) {
    109111                TypeDeclVec typeDecls;
     112                typeDecls.reserve( old.size() );
    110113                for ( const ast::TypeDecl * typeDecl : old ) {
    111114                        typeDecls.push_back( ast::mutate_field( typeDecl,
     
    123126                mut->assertions = expandAssertions( decl->assertions );
    124127                // Update the assertion list on the type as well.
    125                 auto mutType = ast::mutate( mut->type.get() );
    126                 mutType->assertions.clear();
    127                 for ( auto & assertion : mut->assertions ) {
    128                         mutType->assertions.emplace_back(
    129                                 new ast::VariableExpr( mut->location, assertion ) );
    130                 }
    131                 mut->type = mutType;
    132                 return mut;
     128                return updateAssertions( mut );
    133129        }
    134130
     
    154150                const std::vector<ast::ptr<ast::DeclWithType>> & assertions ) {
    155151        std::vector<ast::ptr<ast::DeclWithType>> ret;
     152        ret.reserve( assertions.size() );
    156153        for ( const auto & assn : assertions ) {
    157154                bool isVoid = false;
     
    187184        }
    188185
     186        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ) {
     187                if ( decl->assertions.empty() ) {
     188                        return decl;
     189                }
     190                return updateAssertions( mutate( decl ) );
     191        }
     192
    189193        const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
    190194                if ( decl->params.empty() ) {
     
    204208};
    205209
    206 struct OberatorChecker final {
     210struct OperatorChecker final {
    207211        void previsit( const ast::ObjectDecl * obj ) {
    208                 if ( CodeGen::isOperator( obj->name ) ) {
    209                         auto type = obj->type->stripDeclarator();
    210                         if ( ! dynamic_cast< const ast::FunctionType * >( type ) ) {
    211                                 SemanticError( obj->location,
    212                                         toCString( "operator ", obj->name.c_str(), " is not "
    213                                         "a function or function pointer." ) );
    214                         }
    215                 }
     212                if ( !CodeGen::isOperator( obj->name ) ) return;
     213                auto type = obj->type->stripDeclarator();
     214                if ( dynamic_cast< const ast::FunctionType * >( type ) ) return;
     215                SemanticError( obj->location,
     216                        toCString( "operator ", obj->name.c_str(),
     217                        " is not a function or function pointer." ) );
    216218        }
    217219};
     
    234236        ast::Pass<TraitExpander>::run( transUnit );
    235237        ast::Pass<AssertionFunctionFixer>::run( transUnit );
    236         ast::Pass<OberatorChecker>::run( transUnit );
     238        ast::Pass<OperatorChecker>::run( transUnit );
     239}
     240
     241void fixUniqueIds( ast::TranslationUnit & transUnit ) {
    237242        ast::Pass<UniqueFixCore>::run( transUnit );
    238243}
  • src/Validate/ForallPointerDecay.hpp

    r92355883 r2a301ff  
    2727
    2828/// Cleans up assertion lists and expands traits.
    29 /// Also checks that operator names are used properly on functions and
    30 /// assigns unique IDs. This is a "legacy" pass.
     29/// Also checks that operator names are used properly on functions.
     30/// This is a "legacy" pass.
     31/// Must happen before auto-gen routines are added.
     32void decayForallPointers( ast::TranslationUnit & transUnit );
     33
     34/// Sets uniqueIds on any declarations that do not have one set.
    3135/// Must be after implement concurrent keywords; because uniqueIds must be
    3236/// set on declaration before resolution.
    33 /// Must happen before auto-gen routines are added.
    34 void decayForallPointers( ast::TranslationUnit & transUnit );
     37void fixUniqueIds( ast::TranslationUnit & transUnit );
    3538
    3639/// Expand all traits in an assertion list.
  • src/Validate/GenericParameter.cpp

    r92355883 r2a301ff  
    1616#include "GenericParameter.hpp"
    1717
    18 #include "AST/Copy.hpp"
    1918#include "AST/Decl.hpp"
    2019#include "AST/Expr.hpp"
     
    165164
    166165struct TranslateDimensionCore :
    167                 public WithNoIdSymbolTable, public ast::WithGuards {
     166                public WithNoIdSymbolTable, public ast::WithGuards,
     167                public ast::WithVisitorRef<TranslateDimensionCore> {
    168168
    169169        // SUIT: Struct- or Union- InstType
     
    190190
    191191        const ast::TypeDecl * postvisit( const ast::TypeDecl * decl );
     192        const ast::Type * postvisit( const ast::FunctionType * type );
     193        const ast::Type * postvisit( const ast::TypeInstType * type );
     194
    192195        const ast::Expr * postvisit( const ast::DimensionExpr * expr );
    193196        const ast::Expr * postvisit( const ast::Expr * expr );
     
    195198};
    196199
     200// Declaration of type variable: forall( [N] )  ->  forall( N & | sized( N ) )
    197201const ast::TypeDecl * TranslateDimensionCore::postvisit(
    198202                const ast::TypeDecl * decl ) {
     
    206210        }
    207211        return decl;
     212}
     213
     214// Makes postvisit( TypeInstType ) get called on the entries of the function declaration's type's forall list.
     215// Pass.impl.hpp's visit( FunctionType ) does not consider the forall entries to be child nodes.
     216// Workaround is: during the current TranslateDimension pass, manually visit down there.
     217const ast::Type * TranslateDimensionCore::postvisit(
     218                const ast::FunctionType * type ) {
     219        visitor->maybe_accept( type, &ast::FunctionType::forall );
     220        return type;
     221}
     222
     223// Use of type variable, assuming `forall( [N] )` in scope:  void (*)( foo( /*dimension*/ N ) & )  ->  void (*)( foo( /*dtype*/ N ) & )
     224const ast::Type * TranslateDimensionCore::postvisit(
     225                const ast::TypeInstType * type ) {
     226        if ( type->kind == ast::TypeDecl::Dimension ) {
     227                auto mutType = ast::mutate( type );
     228                mutType->kind = ast::TypeDecl::Dtype;
     229                return mutType;
     230        }
     231        return type;
    208232}
    209233
  • src/Validate/LinkReferenceToTypes.cpp

    r92355883 r2a301ff  
    1010// Created On       : Thr Apr 21 11:41:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Sep 20 16:17:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Fri Jul 14  9:19:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    2727struct LinkTypesCore : public WithNoIdSymbolTable,
    2828                public ast::WithCodeLocation,
     29                public ast::WithDeclsToAdd<>,
    2930                public ast::WithGuards,
    3031                public ast::WithShortCircuiting,
     
    6364        template<typename AggrDecl>
    6465        AggrDecl const * renameGenericParams( AggrDecl const * decl );
     66
     67        // This cluster is used to add declarations (before) but outside of
     68        // any "namespaces" which would qualify the names.
     69        bool inNamespace = false;
     70        std::list<ast::ptr<ast::Decl>> declsToAddOutside;
     71        /// The "leaveNamespace" is handled by guard.
     72        void enterNamespace();
     73        /// Puts the decl on the back of declsToAddAfter once traversal is
     74        /// outside of any namespaces.
     75        void addDeclAfterOutside( ast::Decl const * );
    6576};
     77
     78void LinkTypesCore::enterNamespace() {
     79        if ( inNamespace ) return;
     80        inNamespace = true;
     81        GuardAction( [this](){
     82                inNamespace = false;
     83                declsToAddAfter.splice( declsToAddAfter.begin(), declsToAddOutside );
     84        } );
     85}
     86
     87void LinkTypesCore::addDeclAfterOutside( ast::Decl const * decl ) {
     88        if ( inNamespace ) {
     89                declsToAddOutside.emplace_back( decl );
     90        } else {
     91                declsToAddAfter.emplace_back( decl );
     92        }
     93}
    6694
    6795ast::TypeInstType const * LinkTypesCore::postvisit( ast::TypeInstType const * type ) {
     
    81109        ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
    82110        // It's not a semantic error if the enum is not found, just an implicit forward declaration.
    83         if ( decl ) {
    84                 // Just linking in the node.
    85                 auto mut = ast::mutate( type );
    86                 mut->base = decl;
    87                 type = mut;
    88         }
    89         if ( !decl || !decl->body ) {
    90                 auto mut = ast::mutate( type );
     111        // The unset code location is used to detect imaginary declarations.
     112        // (They may never be used for enumerations.)
     113        if ( !decl || decl->location.isUnset() ) {
     114                assert( location );
     115                ast::EnumDecl * mut = new ast::EnumDecl( *location, type->name );
     116                mut->linkage = ast::Linkage::Compiler;
     117                decl = mut;
     118                symtab.addEnum( decl );
     119                addDeclAfterOutside( decl );
     120        }
     121
     122        ast::EnumInstType * mut = ast::mutate( type );
     123
     124        // Just linking in the node.
     125        mut->base = decl;
     126
     127        if ( !decl->body ) {
    91128                forwardEnums[ mut->name ].push_back( mut );
    92                 type = mut;
    93         }
    94         return type;
     129        }
     130        return mut;
    95131}
    96132
     
    98134        ast::StructDecl const * decl = symtab.lookupStruct( type->name );
    99135        // It's not a semantic error if the struct is not found, just an implicit forward declaration.
    100         if ( decl ) {
    101                 // Just linking in the node.
    102                 auto mut = ast::mutate( type );
    103                 mut->base = decl;
    104                 type = mut;
    105         }
    106         if ( !decl || !decl->body ) {
    107                 auto mut = ast::mutate( type );
     136        // The unset code location is used to detect imaginary declarations.
     137        if ( !decl || decl->location.isUnset() ) {
     138                assert( location );
     139                ast::StructDecl * mut = new ast::StructDecl( *location, type->name );
     140                mut->linkage = ast::Linkage::Compiler;
     141                decl = mut;
     142                symtab.addStruct( decl );
     143                addDeclAfterOutside( decl );
     144        }
     145
     146        ast::StructInstType * mut = ast::mutate( type );
     147
     148        // Just linking in the node.
     149        mut->base = decl;
     150
     151        if ( !decl->body ) {
    108152                forwardStructs[ mut->name ].push_back( mut );
    109                 type = mut;
    110         }
    111         return type;
     153        }
     154        return mut;
    112155}
    113156
     
    115158        ast::UnionDecl const * decl = symtab.lookupUnion( type->name );
    116159        // It's not a semantic error if the union is not found, just an implicit forward declaration.
    117         if ( decl ) {
    118                 // Just linking in the node.
    119                 auto mut = ast::mutate( type );
    120                 mut->base = decl;
    121                 type = mut;
    122         }
    123         if ( !decl || !decl->body ) {
    124                 auto mut = ast::mutate( type );
     160        // The unset code location is used to detect imaginary declarations.
     161        if ( !decl || decl->location.isUnset() ) {
     162                assert( location );
     163                ast::UnionDecl * mut = new ast::UnionDecl( *location, type->name );
     164                mut->linkage = ast::Linkage::Compiler;
     165                decl = mut;
     166                symtab.addUnion( decl );
     167                addDeclAfterOutside( decl );
     168        }
     169
     170        ast::UnionInstType * mut = ast::mutate( type );
     171
     172        // Just linking in the node.
     173        mut->base = decl;
     174
     175        if ( !decl->body ) {
    125176                forwardUnions[ mut->name ].push_back( mut );
    126                 type = mut;
    127         }
    128         return type;
     177        }
     178        return mut;
    129179}
    130180
     
    228278
    229279ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) {
     280        enterNamespace();
    230281        return renameGenericParams( decl );
    231282}
     
    246297
    247298ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) {
     299        enterNamespace();
    248300        return renameGenericParams( decl );
    249301}
     
    264316
    265317ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) {
    266         auto mut = ast::mutate( decl );
    267         if ( mut->name == "sized" ) {
    268                 // "sized" is a special trait - flick the sized status on for the type variable.
    269                 assertf( mut->params.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", decl->params.size() );
    270                 ast::TypeDecl * td = mut->params.front().get_and_mutate();
    271                 td->sized = true;
    272         }
    273 
    274318        // There is some overlap with code from decayForallPointers,
    275319        // perhaps reorganization or shared helper functions are called for.
    276320        // Move assertions from type parameters into the body of the trait.
     321        auto mut = ast::mutate( decl );
    277322        for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) {
    278323                auto expanded = expandAssertions( td->assertions );
  • src/Validate/NoIdSymbolTable.hpp

    r92355883 r2a301ff  
    4646        FORWARD_1( addUnion , const ast::UnionDecl *     )
    4747        FORWARD_1( addTrait , const ast::TraitDecl *     )
    48         FORWARD_1( addStruct, const std::string &        )
    49         FORWARD_1( addUnion , const std::string &        )
    5048        FORWARD_2( addWith  , const std::vector< ast::ptr<ast::Expr> > &, const ast::Decl * )
     49        FORWARD_1( addStructId, const std::string & )
     50        FORWARD_1( addUnionId , const std::string & )
    5151
    5252        FORWARD_1( globalLookupType, const std::string & )
  • src/Validate/ReplaceTypedef.cpp

    r92355883 r2a301ff  
    2020#include "Common/ScopedMap.h"
    2121#include "Common/UniqueName.h"
    22 #include "Common/utility.h"
    2322#include "ResolvExpr/Unify.h"
    2423
     
    294293                aggrDecl->name, ast::Storage::Classes(), type, aggrDecl->linkage );
    295294        // Add the implicit typedef to the AST.
    296         declsToAddBefore.push_back( ast::deepCopy( typeDecl.get() ) );
     295        declsToAddAfter.push_back( ast::deepCopy( typeDecl.get() ) );
    297296        // Shore the name in the map of names.
    298297        typedefNames[ aggrDecl->name ] =
     
    316315        auto mut = ast::mutate( decl );
    317316
    318         std::vector<ast::ptr<ast::Decl>> members;
     317        std::list<ast::ptr<ast::Decl>> members;
    319318        // Unroll accept_all for decl->members so that implicit typedefs for
    320319        // nested types are added to the aggregate body.
    321320        for ( ast::ptr<ast::Decl> const & member : mut->members ) {
     321                assert( declsToAddBefore.empty() );
    322322                assert( declsToAddAfter.empty() );
    323323                ast::Decl const * newMember = nullptr;
     
    328328                }
    329329                if ( !declsToAddBefore.empty() ) {
    330                         for ( auto declToAdd : declsToAddBefore ) {
    331                                 members.push_back( declToAdd );
    332                         }
    333                         declsToAddBefore.clear();
     330                        members.splice( members.end(), declsToAddBefore );
    334331                }
    335332                members.push_back( newMember );
    336         }
     333                if ( !declsToAddAfter.empty() ) {
     334                        members.splice( members.end(), declsToAddAfter );
     335                }
     336        }
     337        assert( declsToAddBefore.empty() );
    337338        assert( declsToAddAfter.empty() );
    338339        if ( !errors.isEmpty() ) { throw errors; }
  • src/Virtual/VirtualDtor.cpp

    r92355883 r2a301ff  
    141141        auto structIter = structDecls.find( instType->aggr() );
    142142        if ( structIter == structDecls.end() ) return;
     143
     144        // If first param not named we need to name it to use it
     145        if ( decl->params.at(0)->name == "" )
     146            mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param";
    143147
    144148        if ( decl->name == "^?{}") {
  • src/main.cc

    r92355883 r2a301ff  
    334334                PASS( "Link Reference To Types", Validate::linkReferenceToTypes, transUnit );
    335335
     336                PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
    336337                PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
    337338                PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
     
    342343                PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit );
    343344                PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
    344                 PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
    345         PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
     345                PASS( "Fix Unique Ids", Validate::fixUniqueIds, transUnit );
    346346                PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
    347347
     
    370370                PASS( "Translate Throws", ControlStruct::translateThrows, transUnit );
    371371                PASS( "Fix Labels", ControlStruct::fixLabels, transUnit );
     372                PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
    372373                PASS( "Fix Names", CodeGen::fixNames, transUnit );
    373374                PASS( "Gen Init", InitTweak::genInit, transUnit );
Note: See TracChangeset for help on using the changeset viewer.