Changeset 54dd994 for src


Ignore:
Timestamp:
Jun 24, 2019, 10:30:47 AM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
84917e2
Parents:
3c6e417 (diff), 9e0a360 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Location:
src
Files:
27 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Expr.hpp

    r3c6e417 r54dd994  
    248248        AddressExpr( const CodeLocation & loc, const Expr * a );
    249249
     250        /// Generate AddressExpr wrapping given expression at same location
     251        AddressExpr( const Expr * a ) : AddressExpr( a->location, a ) {}
     252
    250253        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    251254private:
     
    281284        /// Cast-to-void
    282285        CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast );
     286
     287        /// Wrap a cast expression around an existing expression (always generated)
     288        CastExpr( const Expr * a, const Type * to ) : CastExpr( a->location, a, to, GeneratedCast ) {}
     289
     290        /// Wrap a cast-to-void expression around an existing expression (always generated)
     291        CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {}
    283292
    284293        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Init.hpp

    r3c6e417 r54dd994  
    5555        ConstructFlag maybeConstructed;
    5656
    57         Init( const CodeLocation& loc, ConstructFlag mc ) : ParseNode( loc ), maybeConstructed( mc ) {}
     57        Init( const CodeLocation & loc, ConstructFlag mc ) : ParseNode( loc ), maybeConstructed( mc ) {}
    5858
    59         const Init * accept( Visitor& v ) const override = 0;
     59        const Init * accept( Visitor & v ) const override = 0;
    6060private:
    6161        Init * clone() const override = 0;
     
    6969        ptr<Expr> value;
    7070
    71         SingleInit( const CodeLocation& loc, Expr* val, ConstructFlag mc = DoConstruct )
     71        SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = DoConstruct )
    7272        : Init( loc, mc ), value( val ) {}
    7373
     
    8787        std::vector<ptr<Designation>> designations;
    8888
    89         ListInit( const CodeLocation& loc, std::vector<ptr<Init>>&& is,
    90                 std::vector<ptr<Designation>>&& ds = {}, ConstructFlag mc = DoConstruct );
     89        ListInit( const CodeLocation & loc, std::vector<ptr<Init>> && is,
     90                std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = DoConstruct );
    9191
    9292        using iterator = std::vector<ptr<Init>>::iterator;
     
    114114        ptr<Init> init;
    115115
    116         ConstructorInit( const CodeLocation& loc, Stmt* ctor, Stmt* dtor, Init* init )
     116        ConstructorInit(
     117                const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init )
    117118        : Init( loc, DoConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
    118119
  • src/AST/Node.hpp

    r3c6e417 r54dd994  
    1717
    1818#include <cassert>
     19#include <cstddef>     // for nullptr_t
    1920#include <iosfwd>
    2021#include <type_traits> // for remove_reference
     
    181182        }
    182183
     184        ptr_base & operator=( std::nullptr_t ) {
     185                if ( node ) _dec(node);
     186                node = nullptr;
     187                return *this;
     188        }
     189
    183190        ptr_base & operator=( const ptr_base & o ) {
    184191                assign(o.node);
  • src/AST/Stmt.hpp

    r3c6e417 r54dd994  
    6161        CompoundStmt( CompoundStmt&& o ) = default;
    6262
    63         void push_back( Stmt * s ) { kids.emplace_back( s ); }
    64         void push_front( Stmt * s ) { kids.emplace_front( s ); }
     63        void push_back( const Stmt * s ) { kids.emplace_back( s ); }
     64        void push_front( const Stmt * s ) { kids.emplace_front( s ); }
    6565
    6666        const CompoundStmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    143143
    144144        IfStmt( const CodeLocation & loc, const Expr * cond, const Stmt * thenPart,
    145                 Stmt * const elsePart, std::vector<ptr<Stmt>> && inits,
     145                const Stmt * elsePart = nullptr, std::vector<ptr<Stmt>> && inits = {},
    146146                std::vector<Label> && labels = {} )
    147147        : Stmt(loc, std::move(labels)), cond(cond), thenPart(thenPart), elsePart(elsePart),
  • src/Common/utility.h

    r3c6e417 r54dd994  
    1616#pragma once
    1717
     18#include <cassert>
    1819#include <cctype>
    1920#include <algorithm>
     
    2728#include <type_traits>
    2829#include <utility>
    29 
    30 #include <cassert>
     30#include <vector>
    3131
    3232#include "Common/Indenter.h"
    3333
    3434class Expression;
     35
     36/// bring std::move into global scope
     37using std::move;
     38
     39/// partner to move that copies any copyable type
     40template<typename T>
     41T copy( const T & x ) { return x; }
    3542
    3643template< typename T >
     
    145152                return ret;
    146153        } // switch
     154}
     155
     156/// Splice src onto the end of dst, clearing src
     157template< typename T >
     158void splice( std::vector< T > & dst, std::vector< T > & src ) {
     159        dst.reserve( dst.size() + src.size() );
     160        for ( T & x : src ) { dst.emplace_back( std::move( x ) ); }
     161        src.clear();
     162}
     163
     164/// Splice src onto the begining of dst, clearing src
     165template< typename T >
     166void spliceBegin( std::vector< T > & dst, std::vector< T > & src ) {
     167        splice( src, dst );
     168        dst.swap( src );
    147169}
    148170
  • src/InitTweak/FixInit.cc

    r3c6e417 r54dd994  
    11111111                                                arg2 = new MemberExpr( field, new VariableExpr( params.back() ) );
    11121112                                        }
    1113                                         InitExpander srcParam( arg2 );
     1113                                        InitExpander_old srcParam( arg2 );
    11141114                                        // cast away reference type and construct field.
    11151115                                        Expression * thisExpr = new CastExpr( new VariableExpr( thisParam ), thisParam->get_type()->stripReferences()->clone() );
  • src/InitTweak/GenInit.cc

    r3c6e417 r54dd994  
    1818#include <algorithm>                   // for any_of
    1919#include <cassert>                     // for assert, strict_dynamic_cast, assertf
     20#include <deque>
    2021#include <iterator>                    // for back_inserter, inserter, back_inse...
    2122#include <list>                        // for _List_iterator, list
    2223
     24#include "AST/Decl.hpp"
     25#include "AST/Init.hpp"
     26#include "AST/Node.hpp"
     27#include "AST/Stmt.hpp"
    2328#include "CodeGen/OperatorTable.h"
    2429#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
     
    274279                assertf( objDecl, "genCtorDtor passed null objDecl" );
    275280                std::list< Statement * > stmts;
    276                 InitExpander srcParam( maybeClone( arg ) );
     281                InitExpander_old srcParam( maybeClone( arg ) );
    277282                SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl );
    278283                assert( stmts.size() <= 1 );
     
    286291                std::list< Statement * > dtor;
    287292
    288                 InitExpander srcParam( objDecl->get_init() );
    289                 InitExpander nullParam( (Initializer *)NULL );
     293                InitExpander_old srcParam( objDecl->get_init() );
     294                InitExpander_old nullParam( (Initializer *)NULL );
    290295                SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    291296                SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     
    353358                GuardScope( managedTypes );
    354359        }
     360
     361ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) {
     362        // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each
     363        // constructable object
     364        InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
     365       
     366        ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
     367                srcParam, new ast::VariableExpr{ loc, objDecl }, loc, "?{}", objDecl );
     368        ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
     369                nullParam, new ast::VariableExpr{ loc, objDecl }, loc, "^?{}", objDecl,
     370                SymTab::LoopBackward );
     371       
     372        // check that either both ctor and dtor are present, or neither
     373        assert( (bool)ctor == (bool)dtor );
     374
     375        if ( ctor ) {
     376                // need to remember init expression, in case no ctors exist. If ctor does exist, want to
     377                // use ctor expression instead of init.
     378                ctor.strict_as< ast::ImplicitCtorDtorStmt >();
     379                dtor.strict_as< ast::ImplicitCtorDtorStmt >();
     380
     381                return new ast::ConstructorInit{ loc, ctor, dtor, objDecl->init };
     382        }
     383
     384        return nullptr;
     385}
     386
    355387} // namespace InitTweak
    356388
  • src/InitTweak/GenInit.h

    r3c6e417 r54dd994  
    1919#include <string>              // for string
    2020
     21#include "AST/Fwd.hpp"
     22#include "Common/CodeLocation.h"
     23#include "GenPoly/ScopedSet.h" // for ScopedSet
    2124#include "SynTree/SynTree.h"   // for Visitor Nodes
    22 
    23 #include "GenPoly/ScopedSet.h" // for ScopedSet
    2425
    2526namespace InitTweak {
     
    3536        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
    3637        ConstructorInit * genCtorInit( ObjectDecl * objDecl );
     38        ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
    3739
    3840        class ManagedTypes {
  • src/InitTweak/InitTweak.cc

    r3c6e417 r54dd994  
    2222
    2323#include "AST/Expr.hpp"
     24#include "AST/Init.hpp"
     25#include "AST/Node.hpp"
     26#include "AST/Pass.hpp"
    2427#include "AST/Stmt.hpp"
    2528#include "AST/Type.hpp"
     
    8487                };
    8588
    86                 struct InitFlattener : public WithShortCircuiting {
     89                struct InitFlattener_old : public WithShortCircuiting {
    8790                        void previsit( SingleInit * singleInit ) {
    8891                                visit_children = false;
     
    9295                };
    9396
    94         }
     97                struct InitFlattener_new : public ast::WithShortCircuiting {
     98                        std::vector< ast::ptr< ast::Expr > > argList;
     99
     100                        void previsit( const ast::SingleInit * singleInit ) {
     101                                visit_children = false;
     102                                argList.emplace_back( singleInit->value );
     103                        }
     104                };
     105
     106        } // anonymous namespace
    95107
    96108        std::list< Expression * > makeInitList( Initializer * init ) {
    97                 PassVisitor<InitFlattener> flattener;
     109                PassVisitor<InitFlattener_old> flattener;
    98110                maybeAccept( init, flattener );
    99111                return flattener.pass.argList;
     
    112124        }
    113125
    114         class InitExpander::ExpanderImpl {
     126std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
     127        ast::Pass< InitFlattener_new > flattener;
     128        maybe_accept( init, flattener );
     129        return std::move( flattener.pass.argList );
     130}
     131
     132        class InitExpander_old::ExpanderImpl {
    115133        public:
    116134                virtual ~ExpanderImpl() = default;
     
    119137        };
    120138
    121         class InitImpl : public InitExpander::ExpanderImpl {
     139        class InitImpl_old : public InitExpander_old::ExpanderImpl {
    122140        public:
    123                 InitImpl( Initializer * init ) : init( init ) {}
    124                 virtual ~InitImpl() = default;
     141                InitImpl_old( Initializer * init ) : init( init ) {}
     142                virtual ~InitImpl_old() = default;
    125143
    126144                virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) {
     
    136154        };
    137155
    138         class ExprImpl : public InitExpander::ExpanderImpl {
     156        class ExprImpl_old : public InitExpander_old::ExpanderImpl {
    139157        public:
    140                 ExprImpl( Expression * expr ) : arg( expr ) {}
    141                 virtual ~ExprImpl() { delete arg; }
     158                ExprImpl_old( Expression * expr ) : arg( expr ) {}
     159                virtual ~ExprImpl_old() { delete arg; }
    142160
    143161                virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
     
    163181        };
    164182
    165         InitExpander::InitExpander( Initializer * init ) : expander( new InitImpl( init ) ) {}
    166 
    167         InitExpander::InitExpander( Expression * expr ) : expander( new ExprImpl( expr ) ) {}
    168 
    169         std::list< Expression * > InitExpander::operator*() {
     183        InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {}
     184
     185        InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {}
     186
     187        std::list< Expression * > InitExpander_old::operator*() {
    170188                return cur;
    171189        }
    172190
    173         InitExpander & InitExpander::operator++() {
     191        InitExpander_old & InitExpander_old::operator++() {
    174192                cur = expander->next( indices );
    175193                return *this;
     
    177195
    178196        // use array indices list to build switch statement
    179         void InitExpander::addArrayIndex( Expression * index, Expression * dimension ) {
     197        void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) {
    180198                indices.push_back( index );
    181199                indices.push_back( dimension );
    182200        }
    183201
    184         void InitExpander::clearArrayIndices() {
     202        void InitExpander_old::clearArrayIndices() {
    185203                deleteAll( indices );
    186204                indices.clear();
    187205        }
    188206
    189         bool InitExpander::addReference() {
     207        bool InitExpander_old::addReference() {
    190208                bool added = false;
    191209                for ( Expression *& expr : cur ) {
     
    218236
    219237                template< typename OutIterator >
    220                 void build( UntypedExpr * callExpr, InitExpander::IndexList::iterator idx, InitExpander::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
     238                void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
    221239                        if ( idx == idxEnd ) return;
    222240                        Expression * index = *idx++;
     
    275293        // remaining elements.
    276294        // To accomplish this, generate switch statement, consuming all of expander's elements
    277         Statement * InitImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
     295        Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
    278296                if ( ! init ) return nullptr;
    279297                CompoundStmt * block = new CompoundStmt();
     
    288306        }
    289307
    290         Statement * ExprImpl::buildListInit( UntypedExpr *, std::list< Expression * > & ) {
     308        Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) {
    291309                return nullptr;
    292310        }
    293311
    294         Statement * InitExpander::buildListInit( UntypedExpr * dst ) {
     312        Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) {
    295313                return expander->buildListInit( dst, indices );
    296314        }
     315
     316class InitExpander_new::ExpanderImpl {
     317public:
     318        virtual ~ExpanderImpl() = default;
     319        virtual std::vector< ast::ptr< ast::Expr > > next( IndexList & indices ) = 0;
     320        virtual ast::ptr< ast::Stmt > buildListInit(
     321                ast::UntypedExpr * callExpr, IndexList & indices ) = 0;
     322};
     323
     324namespace {
     325        template< typename Out >
     326        void buildCallExpr(
     327                ast::UntypedExpr * callExpr, const ast::Expr * index, const ast::Expr * dimension,
     328                const ast::Init * init, Out & out
     329        ) {
     330                const CodeLocation & loc = init->location;
     331
     332                auto cond = new ast::UntypedExpr{
     333                        loc, new ast::NameExpr{ loc, "?<?" }, { index, dimension } };
     334               
     335                std::vector< ast::ptr< ast::Expr > > args = makeInitList( init );
     336                splice( callExpr->args, args );
     337
     338                out.emplace_back( new ast::IfStmt{ loc, cond, new ast::ExprStmt{ loc, callExpr } } );
     339
     340                out.emplace_back( new ast::ExprStmt{
     341                        loc, new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, "++?" }, { index } } } );
     342        }
     343
     344        template< typename Out >
     345        void build(
     346                ast::UntypedExpr * callExpr, const InitExpander_new::IndexList & indices,
     347                const ast::Init * init, Out & out
     348        ) {
     349                if ( indices.empty() ) return;
     350
     351                unsigned idx = 0;
     352
     353                const ast::Expr * index = indices[idx++];
     354                assert( idx != indices.size() );
     355                const ast::Expr * dimension = indices[idx++];
     356
     357                if ( idx == indices.size() ) {
     358                        if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) {
     359                                for ( const ast::Init * init : *listInit ) {
     360                                        buildCallExpr( callExpr, index, dimension, init, out );
     361                                }
     362                        } else {
     363                                buildCallExpr( callExpr, index, dimension, init, out );
     364                        }
     365                } else {
     366                        const CodeLocation & loc = init->location;
     367
     368                        unsigned long cond = 0;
     369                        auto listInit = dynamic_cast< const ast::ListInit * >( init );
     370                        if ( ! listInit ) { SemanticError( loc, "unbalanced list initializers" ); }
     371
     372                        static UniqueName targetLabel( "L__autogen__" );
     373                        ast::Label switchLabel{
     374                                loc, targetLabel.newName(), { new ast::Attribute{ "unused" } } };
     375                       
     376                        std::vector< ast::ptr< ast::Stmt > > branches;
     377                        for ( const ast::Init * init : *listInit ) {
     378                                auto condition = ast::ConstantExpr::from_ulong( loc, cond );
     379                                ++cond;
     380
     381                                std::vector< ast::ptr< ast::Stmt > > stmts;
     382                                build( callExpr, indices, init, stmts );
     383                                stmts.emplace_back(
     384                                        new ast::BranchStmt{ loc, ast::BranchStmt::Break, switchLabel } );
     385                                branches.emplace_back( new ast::CaseStmt{ loc, condition, std::move( stmts ) } );
     386                        }
     387                        out.emplace_back( new ast::SwitchStmt{ loc, index, std::move( branches ) } );
     388                        out.emplace_back( new ast::NullStmt{ loc, { switchLabel } } );
     389                }
     390        }
     391
     392        class InitImpl_new final : public InitExpander_new::ExpanderImpl {
     393                ast::ptr< ast::Init > init;
     394        public:
     395                InitImpl_new( const ast::Init * i ) : init( i ) {}
     396
     397                std::vector< ast::ptr< ast::Expr > > next( InitExpander_new::IndexList & ) override {
     398                        return makeInitList( init );
     399                }
     400               
     401                ast::ptr< ast::Stmt > buildListInit(
     402                        ast::UntypedExpr * callExpr, InitExpander_new::IndexList & indices
     403                ) override {
     404                        // If array came with an initializer list, initialize each element. We may have more
     405                        // initializers than elements of the array; need to check at each index that we have
     406                        // not exceeded size. We may have fewer initializers than elements in the array; need
     407                        // to default-construct remaining elements. To accomplish this, generate switch
     408                        // statement consuming all of expander's elements
     409
     410                        if ( ! init ) return {};
     411
     412                        std::list< ast::ptr< ast::Stmt > > stmts;
     413                        build( callExpr, indices, init, stmts );
     414                        if ( stmts.empty() ) {
     415                                return {};
     416                        } else {
     417                                auto block = new ast::CompoundStmt{ init->location, std::move( stmts ) };
     418                                init = nullptr;  // consumed in creating the list init
     419                                return block;
     420                        }
     421                }
     422        };
     423
     424        class ExprImpl_new final : public InitExpander_new::ExpanderImpl {
     425                ast::ptr< ast::Expr > arg;
     426        public:
     427                ExprImpl_new( const ast::Expr * a ) : arg( a ) {}
     428
     429                std::vector< ast::ptr< ast::Expr > > next(
     430                        InitExpander_new::IndexList & indices
     431                ) override {
     432                        if ( ! arg ) return {};
     433
     434                        const CodeLocation & loc = arg->location;
     435                        const ast::Expr * expr = arg;
     436                        for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) {
     437                                // go through indices and layer on subscript exprs ?[?]
     438                                ++it;
     439                                expr = new ast::UntypedExpr{
     440                                        loc, new ast::NameExpr{ loc, "?[?]" }, { expr, *it } };
     441                        }
     442                        return { expr };
     443                }
     444               
     445                ast::ptr< ast::Stmt > buildListInit(
     446                        ast::UntypedExpr *, InitExpander_new::IndexList &
     447                ) override {
     448                        return {};
     449                }
     450        };
     451} // anonymous namespace
     452
     453InitExpander_new::InitExpander_new( const ast::Init * init )
     454: expander( new InitImpl_new{ init } ), crnt(), indices() {}
     455
     456InitExpander_new::InitExpander_new( const ast::Expr * expr )
     457: expander( new ExprImpl_new{ expr } ), crnt(), indices() {}
     458
     459std::vector< ast::ptr< ast::Expr > > InitExpander_new::operator* () { return crnt; }
     460
     461InitExpander_new & InitExpander_new::operator++ () {
     462        crnt = expander->next( indices );
     463        return *this;
     464}
     465
     466/// builds statement which has the same semantics as a C-style list initializer (for array
     467/// initializers) using callExpr as the base expression to perform initialization
     468ast::ptr< ast::Stmt > InitExpander_new::buildListInit( ast::UntypedExpr * callExpr ) {
     469        return expander->buildListInit( callExpr, indices );
     470}
     471
     472void InitExpander_new::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
     473        indices.emplace_back( index );
     474        indices.emplace_back( dimension );
     475}
     476
     477void InitExpander_new::clearArrayIndices() { indices.clear(); }
     478
     479bool InitExpander_new::addReference() {
     480        for ( ast::ptr< ast::Expr > & expr : crnt ) {
     481                expr = new ast::AddressExpr{ expr };
     482        }
     483        return ! crnt.empty();
     484}
    297485
    298486        Type * getTypeofThis( FunctionType * ftype ) {
  • src/InitTweak/InitTweak.h

    r3c6e417 r54dd994  
    4444        /// transform Initializer into an argument list that can be passed to a call expression
    4545        std::list< Expression * > makeInitList( Initializer * init );
     46        std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
    4647
    4748        /// True if the resolver should try to construct dwt
     
    101102        bool isConstExpr( Initializer * init );
    102103
    103         class InitExpander {
     104        class InitExpander_old {
    104105        public:
    105106                // expand by stepping through init to get each list of arguments
    106                 InitExpander( Initializer * init );
     107                InitExpander_old( Initializer * init );
    107108
    108109                // always expand to expr
    109                 InitExpander( Expression * expr );
     110                InitExpander_old( Expression * expr );
    110111
    111112                // iterator-like interface
    112113                std::list< Expression * > operator*();
    113                 InitExpander & operator++();
     114                InitExpander_old & operator++();
    114115
    115116                // builds statement which has the same semantics as a C-style list initializer
     
    130131                IndexList indices;
    131132        };
     133
     134        class InitExpander_new {
     135        public:
     136                using IndexList = std::vector< ast::ptr< ast::Expr > >;
     137                class ExpanderImpl;
     138
     139        private:
     140                std::shared_ptr< ExpanderImpl > expander;
     141                std::vector< ast::ptr< ast::Expr > > crnt;
     142                // invariant: list of size 2N (elements come in pairs [index, dimension])
     143                IndexList indices;
     144
     145        public:
     146                /// Expand by stepping through init to get each list of arguments
     147                InitExpander_new( const ast::Init * init );
     148
     149                /// Always expand to expression
     150                InitExpander_new( const ast::Expr * expr );
     151
     152                std::vector< ast::ptr< ast::Expr > > operator* ();
     153                InitExpander_new & operator++ ();
     154
     155                /// builds statement which has the same semantics as a C-style list initializer (for array
     156                /// initializers) using callExpr as the base expression to perform initialization.
     157                /// Mutates callExpr
     158                ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr );
     159
     160                void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension );
     161
     162                void clearArrayIndices();
     163
     164                bool addReference();
     165        };
    132166} // namespace
    133167
  • src/ResolvExpr/Alternative.cc

    r3c6e417 r54dd994  
    125125        }
    126126
    127         void splice( AltList& dst, AltList& src ) {
    128                 dst.reserve( dst.size() + src.size() );
    129                 for ( Alternative& alt : src ) {
    130                         dst.push_back( std::move(alt) );
    131                 }
    132                 src.clear();
    133         }
    134 
    135         void spliceBegin( AltList& dst, AltList& src ) {
    136                 splice( src, dst );
    137                 dst.swap( src );
    138         }
    139 
    140127} // namespace ResolvExpr
    141128
  • src/ResolvExpr/Alternative.h

    r3c6e417 r54dd994  
    112112        typedef std::vector< Alternative > AltList;
    113113
    114         /// Moves all elements from src to the end of dst
    115         void splice( AltList& dst, AltList& src );
    116 
    117         /// Moves all elements from src to the beginning of dst
    118         void spliceBegin( AltList& dst, AltList& src );
    119 
    120114        static inline std::ostream & operator<<(std::ostream & os, const ResolvExpr::Alternative & alt) {
    121115                alt.print( os );
  • src/ResolvExpr/AlternativeFinder.cc

    r3c6e417 r54dd994  
    5656#define PRINT( text ) if ( resolvep ) { text }
    5757//#define DEBUG_COST
    58 
    59 using std::move;
    60 
    61 /// copies any copyable type
    62 template<typename T>
    63 T copy(const T& x) { return x; }
    6458
    6559namespace ResolvExpr {
  • src/ResolvExpr/Candidate.hpp

    r3c6e417 r54dd994  
    7575using CandidateList = std::vector< CandidateRef >;
    7676
    77 /// Splice src after dst, clearing src
    78 static inline void splice( CandidateList & dst, CandidateList & src ) {
    79         dst.reserve( dst.size() + src.size() );
    80         for ( CandidateRef & r : src ) { dst.emplace_back( std::move( r ) ); }
    81         src.clear();
    82 }
    83 
    84 /// Splice src before dst
    85 static inline void spliceBegin( CandidateList & dst, CandidateList & src ) {
    86         splice( src, dst );
    87         dst.swap( src );
    88 }
    89 
    9077/// Sum the cost of a list of candidates
    9178static inline Cost sumCost( const CandidateList & candidates ) {
  • src/ResolvExpr/CandidateFinder.cpp

    r3c6e417 r54dd994  
    3939#include "AST/SymbolTable.hpp"
    4040#include "AST/Type.hpp"
     41#include "Common/utility.h"       // for move, copy
    4142#include "SymTab/Mangler.h"
    4243#include "SymTab/Validate.h"      // for validateType
     
    4647
    4748namespace ResolvExpr {
    48 
    49 using std::move;
    50 
    51 /// partner to move that copies any copyable type
    52 template<typename T>
    53 T copy( const T & x ) { return x; }
    5449
    5550const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) {
     
    5752                // cast away reference from expr
    5853                cost.incReference();
    59                 return new ast::CastExpr{ expr->location, expr, expr->result->stripReferences() };
     54                return new ast::CastExpr{ expr, expr->result->stripReferences() };
    6055        }
    6156       
     
    126121                        ast::ptr< ast::Type > newType = paramType;
    127122                        env.apply( newType );
    128                         return new ast::CastExpr{ arg->location, arg, newType };
     123                        return new ast::CastExpr{ arg, newType };
    129124
    130125                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     
    793788                       
    794789                        if ( aggrType.as< ast::ReferenceType >() ) {
    795                                 aggrExpr =
    796                                         new ast::CastExpr{ aggrExpr->location, aggrExpr, aggrType->stripReferences() };
     790                                aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
    797791                        }
    798792
  • src/ResolvExpr/Cost.h

    r3c6e417 r54dd994  
    1010// Created On       : Sun May 17 09:39:50 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 29 18:33:44 2019
    13 // Update Count     : 49
     12// Last Modified On : Fri Jun 21 11:39:13 2019
     13// Update Count     : 63
    1414//
    1515
     
    2121
    2222namespace ResolvExpr {
    23 #if 0
    24 
    25         //*************************** OLD ***************************
    26 
    27         class Cost {
    28           private:
    29                 Cost( int unsafeCost, int polyCost, int safeCost, int signCost,
    30                           int varCost, int specCost, int referenceCost );
    31           public:
    32                 Cost & incUnsafe( int inc = 1 );
    33                 Cost & incPoly( int inc = 1 );
    34                 Cost & incSafe( int inc = 1 );
    35                 Cost & incSign( int inc = 1 );
    36                 Cost & incVar( int inc = 1 );
    37                 Cost & decSpec( int inc = 1 );
    38                 Cost & incReference( int inc = 1 );
    39 
    40                 int get_unsafeCost() const { return unsafeCost; }
    41                 int get_polyCost() const { return polyCost; }
    42                 int get_safeCost() const { return safeCost; }
    43                 int get_signCost() const { return signCost; }
    44                 int get_varCost() const { return varCost; }
    45                 int get_specCost() const { return specCost; }
    46                 int get_referenceCost() const { return referenceCost; }
    47 
    48                 Cost operator+( const Cost &other ) const;
    49                 Cost &operator+=( const Cost &other );
    50                 bool operator<( const Cost &other ) const;
    51                 bool operator==( const Cost &other ) const;
    52                 bool operator!=( const Cost &other ) const;
    53                 friend std::ostream &operator<<( std::ostream &os, const Cost &cost );
    54                 // returns negative for *this < other, 0 for *this == other, positive for *this > other
    55                 int compare( const Cost &other ) const;
    56 
    57                 static const Cost zero;
    58                 static const Cost infinity;
    59 
    60                 static const Cost unsafe;
    61                 static const Cost poly;
    62                 static const Cost safe;
    63                 static const Cost sign;
    64                 static const Cost var;
    65                 static const Cost spec;
    66                 static const Cost reference;
    67 
    68           private:
    69                 int unsafeCost;     ///< Unsafe (narrowing) conversions
    70                 int polyCost;       ///< Count of parameters and return values bound to some poly type
    71                 int safeCost;       ///< Safe (widening) conversions
    72                 int signCost;       ///< Count of safe sign conversions
    73                 int varCost;        ///< Count of polymorphic type variables
    74                 int specCost;       ///< Polymorphic type specializations (type assertions), negative cost
    75                 int referenceCost;  ///< reference conversions
    76         };
    77 
    78         inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int signCost,
    79                                            int varCost, int specCost, int referenceCost )
    80                 : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), signCost( signCost ),
    81                   varCost( varCost ), specCost( specCost ), referenceCost( referenceCost ) {}
    82 
    83         inline Cost & Cost::incUnsafe( int inc ) {
    84                 if ( *this == infinity ) return *this;
    85                 unsafeCost += inc;
    86                 return *this;
    87         }
    88 
    89         inline Cost & Cost::incPoly( int inc ) {
    90                 if ( *this == infinity ) return *this;
    91                 polyCost += inc;
    92                 return *this;
    93         }
    94 
    95         inline Cost & Cost::incSafe( int inc ) {
    96                 if ( *this == infinity ) return *this;
    97                 safeCost += inc;
    98                 return *this;
    99         }
    100 
    101         inline Cost & Cost::incSign( int inc ) {
    102                 if ( *this == infinity ) return *this;
    103                 signCost += inc;
    104                 return *this;
    105         }
    106 
    107         inline Cost & Cost::incVar( int inc ) {
    108                 if ( *this == infinity ) return *this;
    109                 varCost += inc;
    110                 return *this;
    111         }
    112 
    113         inline Cost& Cost::decSpec( int dec ) {
    114                 if ( *this == infinity ) return *this;
    115                 specCost -= dec;
    116                 return *this;
    117         }
    118 
    119         inline Cost & Cost::incReference( int inc ) {
    120                 if ( *this == infinity ) return *this;
    121                 referenceCost += inc;
    122                 return *this;
    123         }
    124 
    125         inline Cost Cost::operator+( const Cost &other ) const {
    126                 if ( *this == infinity || other == infinity ) return infinity;
    127                 return Cost{
    128                         unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost,
    129                                 signCost + other.signCost, varCost + other.varCost, specCost + other.specCost,
    130                                 referenceCost + other.referenceCost };
    131         }
    132 
    133         inline Cost &Cost::operator+=( const Cost &other ) {
    134                 if ( *this == infinity ) return *this;
    135                 if ( other == infinity ) {
    136                         *this = infinity;
    137                         return *this;
    138                 }
    139                 unsafeCost += other.unsafeCost;
    140                 polyCost += other.polyCost;
    141                 safeCost += other.safeCost;
    142                 signCost += other.signCost;
    143                 varCost += other.varCost;
    144                 specCost += other.specCost;
    145                 referenceCost += other.referenceCost;
    146                 return *this;
    147         }
    148 
    149         inline bool Cost::operator<( const Cost &other ) const {
    150                 if ( *this == infinity ) return false;
    151                 if ( other == infinity ) return true;
    152 
    153                 if ( unsafeCost > other.unsafeCost ) {
    154                         return false;
    155                 } else if ( unsafeCost < other.unsafeCost ) {
    156                         return true;
    157                 } else if ( polyCost > other.polyCost ) {
    158                         return false;
    159                 } else if ( polyCost < other.polyCost ) {
    160                         return true;
    161                 } else if ( safeCost > other.safeCost ) {
    162                         return false;
    163                 } else if ( safeCost < other.safeCost ) {
    164                         return true;
    165                 } else if ( signCost > other.signCost ) {
    166                         return false;
    167                 } else if ( signCost < other.signCost ) {
    168                         return true;
    169                 } else if ( varCost > other.varCost ) {
    170                         return false;
    171                 } else if ( varCost < other.varCost ) {
    172                         return true;
    173                 } else if ( specCost > other.specCost ) {
    174                         return false;
    175                 } else if ( specCost > other.specCost ) {
    176                         return true;
    177                 } else if ( referenceCost > other.referenceCost ) {
    178                         return false;
    179                 } else if ( referenceCost < other.referenceCost ) {
    180                         return true;
    181                 } else {
    182                         return false;
    183                 } // if
    184         }
    185 
    186         inline int Cost::compare( const Cost &other ) const {
    187                 if ( *this == infinity ) return +1;
    188                 if ( other == infinity ) return -1;
    189 
    190                 int c = unsafeCost - other.unsafeCost; if ( c ) return c;
    191                 c = polyCost - other.polyCost; if ( c ) return c;
    192                 c = safeCost - other.safeCost; if ( c ) return c;
    193                 c = signCost - other.signCost; if ( c ) return c;
    194                 c = varCost - other.varCost; if ( c ) return c;
    195                 c = specCost - other.specCost; if ( c ) return c;
    196                 return referenceCost - other.referenceCost;
    197         }
    198 
    199         inline bool Cost::operator==( const Cost &other ) const {
    200                 return unsafeCost == other.unsafeCost
    201                         && polyCost == other.polyCost
    202                         && safeCost == other.safeCost
    203                         && signCost == other.signCost
    204                         && varCost == other.varCost
    205                         && specCost == other.specCost
    206                         && referenceCost == other.referenceCost;
    207         }
    208 
    209         inline bool Cost::operator!=( const Cost &other ) const {
    210                 return !( *this == other );
    211         }
    212 
    213         inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
    214                 return os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", "
    215                           << cost.safeCost << ", " << cost.signCost << ", "
    216                                   << cost.varCost << ", " << cost.specCost << ", "
    217                           << cost.referenceCost << " )";
    218         }
    219 
    220 #else
    221 
    222         //*************************** NEW ***************************
    223 
    22423        // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the
    22524        // specialization cost is a negative value so a correction is needed is a few places.
     
    371170                                  << ", " << cost.get_referenceCost() << " )";
    372171        }
    373 #endif // 0
    374172} // namespace ResolvExpr
    375173
  • src/ResolvExpr/RenameVars.cc

    r3c6e417 r54dd994  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:05:18 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 30 17:07:57 2019
    13 // Update Count     : 7
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Jun 20 17:39:00 2019
     13// Update Count     : 8
    1414//
    1515
     
    1919#include <utility>                 // for pair
    2020
     21#include "AST/Pass.hpp"
     22#include "AST/Type.hpp"
    2123#include "Common/PassVisitor.h"
     24#include "Common/ScopedMap.h"
    2225#include "Common/SemanticError.h"  // for SemanticError
    2326#include "RenameVars.h"
     
    2831
    2932namespace ResolvExpr {
    30         namespace {
    31                 struct RenameVars {
    32                         RenameVars();
    33                         void reset();
    3433
    35                         void previsit( TypeInstType * instType );
    36                         void previsit( Type * );
    37                         void postvisit( Type * );
     34namespace {
     35        class RenamingData {
     36                int level = 0;
     37                int resetCount = 0;
     38                ScopedMap< std::string, std::string > nameMap;
    3839
    39                   private:
    40                         int level, resetCount;
    41                         std::list< std::unordered_map< std::string, std::string > > mapStack;
    42                 };
    43 
    44                 PassVisitor<RenameVars> global_renamer;
    45         } // namespace
    46 
    47         void renameTyVars( Type * t ) {
    48                 t->accept( global_renamer );
    49         }
    50 
    51         void resetTyVarRenaming() {
    52                 global_renamer.pass.reset();
    53         }
    54 
    55         namespace {
    56                 RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) {
    57                         mapStack.push_front( std::unordered_map< std::string, std::string >() );
     40        public:
     41                void reset() {
     42                        level = 0;
     43                        ++resetCount;
    5844                }
    5945
    60                 void RenameVars::reset() {
    61                         level = 0;
    62                         resetCount++;
     46                using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;
     47
     48                void rename( TypeInstType * type ) {
     49                        mapConstIterator it = nameMap.find( type->name );
     50                        if ( it != nameMap.end() ) {
     51                                type->name = it->second;
     52                        }
    6353                }
    6454
    65                 void RenameVars::previsit( TypeInstType * instType ) {
    66                         previsit( (Type *)instType );
    67                         std::unordered_map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name );
    68                         if ( i != mapStack.front().end() ) {
    69                                 instType->name = i->second;
    70                         } // if
    71                 }
    72 
    73                 void RenameVars::previsit( Type * type ) {
     55                void openLevel( Type * type ) {
    7456                        if ( ! type->forall.empty() ) {
    75                                 // copies current name mapping into new mapping
    76                                 mapStack.push_front( mapStack.front() );
     57                                nameMap.beginScope();
    7758                                // renames all "forall" type names to `_${level}_${name}'
    7859                                for ( auto td : type->forall ) {
     
    8061                                        output << "_" << resetCount << "_" << level << "_" << td->name;
    8162                                        std::string newname( output.str() );
    82                                         mapStack.front()[ td->get_name() ] = newname;
     63                                        nameMap[ td->get_name() ] = newname;
    8364                                        td->name = newname;
    8465                                        // ditto for assertion names, the next level in
     
    8970                }
    9071
    91                 void RenameVars::postvisit( Type * type ) {
    92                         // clears name mapping added by typeBefore()
    93                         if ( ! type->forall.empty() ) {
    94                                 mapStack.pop_front();
    95                         } // if
     72                void closeLevel( Type * type ) {
     73                        if ( !type->forall.empty() ) {
     74                                nameMap.endScope();
     75                        }
    9676                }
    97         } // namespace
    9877
    99         const ast::Type * renameTyVars( const ast::Type * t ) {
    100                 #warning unimplemented; make sure resetTyVarRenaming() updated when implemented
    101                 (void)t;
    102                 assert(false);
    103                 return t;
    104         }
     78                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
     79                        mapConstIterator it = nameMap.find( type->name );
     80                        if ( it != nameMap.end() ) {
     81                                ast::TypeInstType * mutType = ast::mutate( type );
     82                                mutType->name = it->second;
     83                    type = mutType;
     84                        }
     85                        return type;
     86                }
     87
     88                template<typename NodeT>
     89                const NodeT * openLevel( const NodeT * type ) {
     90                        if ( !type->forall.empty() ) {
     91                                nameMap.beginScope();
     92                                // Load new names from this forall clause and perform renaming.
     93                                NodeT * mutType = ast::mutate( type );
     94                                for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
     95                                        std::ostringstream output;
     96                                        output << "_" << resetCount << "_" << level << "_" << td->name;
     97                                        std::string newname( output.str() );
     98                                        nameMap[ td->name ] = newname;
     99                                        ++level;
     100
     101                                        ast::TypeDecl * decl = ast::mutate( td.get() );
     102                                        decl->name = newname;
     103                                        td = decl;
     104                                }
     105                        }
     106                        return type;
     107                }
     108
     109                template<typename NodeT>
     110                const NodeT * closeLevel( const NodeT * type ) {
     111                        if ( !type->forall.empty() ) {
     112                                nameMap.endScope();
     113                        }
     114                        return type;
     115                }
     116        };
     117
     118        // Global State:
     119        RenamingData renaming;
     120
     121        struct RenameVars {
     122                void previsit( TypeInstType * instType ) {
     123                        renaming.openLevel( (Type*)instType );
     124                        renaming.rename( instType );
     125                }
     126                void previsit( Type * type ) {
     127                        renaming.openLevel( type );
     128                }
     129                void postvisit( Type * type ) {
     130                        renaming.closeLevel( type );
     131                }
     132
     133                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
     134                        return renaming.openLevel( type );
     135                }
     136                const ast::StructInstType * previsit( const ast::StructInstType * type ) {
     137                        return renaming.openLevel( type );
     138                }
     139                const ast::UnionInstType * previsit( const ast::UnionInstType * type ) {
     140                        return renaming.openLevel( type );
     141                }
     142                const ast::TraitInstType * previsit( const ast::TraitInstType * type ) {
     143                        return renaming.openLevel( type );
     144                }
     145                const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
     146                        return renaming.rename( renaming.openLevel( type ) );
     147                }
     148                const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) {
     149                        return renaming.closeLevel( type );
     150                }
     151        };
     152
     153} // namespace
     154
     155void renameTyVars( Type * t ) {
     156        PassVisitor<RenameVars> renamer;
     157        t->accept( renamer );
     158}
     159
     160const ast::Type * renameTyVars( const ast::Type * t ) {
     161        ast::Pass<RenameVars> renamer;
     162        return t->accept( renamer );
     163}
     164
     165void resetTyVarRenaming() {
     166        renaming.reset();
     167}
     168
    105169} // namespace ResolvExpr
    106170
  • src/ResolvExpr/Resolver.cc

    r3c6e417 r54dd994  
    11091109               
    11101110                // set up and resolve expression cast to void
    1111                 ast::CastExpr * untyped = new ast::CastExpr{ expr->location, expr };
     1111                ast::CastExpr * untyped = new ast::CastExpr{ expr };
    11121112                CandidateRef choice = findUnfinishedKindExpression(
    11131113                        untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
     
    11611161                ) {
    11621162                        assert( untyped && type );
    1163                         ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped->location, untyped, type };
     1163                        ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
    11641164                        ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
    11651165                        removeExtraneousCast( newExpr, symtab );
     
    12511251                ast::Pass< Resolver_new > resolver;
    12521252                accept_all( translationUnit, resolver );
     1253        }
     1254
     1255        ast::ptr< ast::Init > resolveCtorInit(
     1256                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab
     1257        ) {
     1258                assert( ctorInit );
     1259                ast::Pass< Resolver_new > resolver{ symtab };
     1260                return ctorInit->accept( resolver );
    12531261        }
    12541262
  • src/ResolvExpr/Resolver.h

    r3c6e417 r54dd994  
    2929
    3030namespace ast {
     31        class ConstructorInit;
    3132        class Decl;
    3233        class DeletedExpr;
     34        class Init;
    3335        class StmtExpr;
    3436        class SymbolTable;
     
    5961        ast::ptr< ast::Expr > resolveInVoidContext(
    6062                const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env );
     63        /// Resolves a constructor init expression
     64        ast::ptr< ast::Init > resolveCtorInit(
     65                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
    6166        /// Resolves a statement expression
    6267        ast::ptr< ast::Expr > resolveStmtExpr(
  • src/SymTab/Autogen.cc

    r3c6e417 r54dd994  
    2424#include <vector>                  // for vector
    2525
     26#include "AST/Decl.hpp"
    2627#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
    2728#include "Common/PassVisitor.h"    // for PassVisitor
     
    209210        }
    210211
     212        bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
     213                return obj && obj->name.empty() && obj->bitfieldWidth;
     214        }
     215
    211216        /// inserts a forward declaration for functionDecl into declsToAdd
    212217        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
     
    388393
    389394        void StructFuncGenerator::makeMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool forward ) {
    390                 InitTweak::InitExpander srcParam( src );
     395                InitTweak::InitExpander_old srcParam( src );
    391396
    392397                // assign to destination
  • src/SymTab/Autogen.h

    r3c6e417 r54dd994  
    1717
    1818#include <cassert>                // for assert
     19#include <iterator>               // for back_inserter
    1920#include <string>                 // for string
    2021
     22#include "AST/Decl.hpp"
     23#include "AST/Expr.hpp"
     24#include "AST/Init.hpp"
     25#include "AST/Node.hpp"
     26#include "AST/Stmt.hpp"
     27#include "AST/Type.hpp"
    2128#include "CodeGen/OperatorTable.h"
    2229#include "Common/UniqueName.h"    // for UniqueName
     30#include "Common/utility.h"       // for splice
    2331#include "InitTweak/InitTweak.h"  // for InitExpander
    2432#include "SynTree/Constant.h"     // for Constant
     
    3644        /// returns true if obj's name is the empty string and it has a bitfield width
    3745        bool isUnnamedBitfield( ObjectDecl * obj );
     46        bool isUnnamedBitfield( const ast::ObjectDecl * obj );
    3847
    3948        /// generate the type of an assignment function for paramType.
     
    4958        FunctionType * genCopyType( Type * paramType, bool maybePolymorphic = true );
    5059
     60        /// Enum for loop direction
     61        enum LoopDirection { LoopBackward, LoopForward };
     62
    5163        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
    5264        template< typename OutputIterator >
    53         Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true );
     65        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true );
     66
     67        template< typename OutIter >
     68        ast::ptr< ast::Stmt > genCall(
     69                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     70                const CodeLocation & loc, const std::string & fname, OutIter && out,
     71                const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
    5472
    5573        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
    5674        /// optionally returns a statement which must be inserted prior to the containing loop, if there is one
    5775        template< typename OutputIterator >
    58         Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {
     76        Statement * genScalarCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {
    5977                bool isReferenceCtorDtor = false;
    6078                if ( dynamic_cast< ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
     
    106124        }
    107125
     126        /// inserts into out a generated call expression to function fname with arguments dstParam and
     127        /// srcParam. Should only be called with non-array types.
     128        /// optionally returns a statement which must be inserted prior to the containing loop, if
     129        /// there is one
     130        template< typename OutIter >
     131        ast::ptr< ast::Stmt > genScalarCall(
     132                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     133                const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
     134                const ast::Type * addCast = nullptr
     135        ) {
     136                bool isReferenceCtorDtor = false;
     137                if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
     138                        // reference constructors are essentially application of the rebind operator.
     139                        // apply & to both arguments, do not need a cast
     140                        fname = "?=?";
     141                        dstParam = new ast::AddressExpr{ dstParam };
     142                        addCast = nullptr;
     143                        isReferenceCtorDtor = true;
     144                }
     145
     146                // want to be able to generate assignment, ctor, and dtor generically, so fname is one of
     147                // "?=?", "?{}", or "^?{}"
     148                ast::UntypedExpr * fExpr = new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, fname } };
     149
     150                if ( addCast ) {
     151                        // cast to T& with qualifiers removed, so that qualified objects can be constructed and
     152                        // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
     153                        // is considered a qualifier - for AddressExpr to resolve, its argument must have an
     154                        // lvalue-qualified type, so remove all qualifiers except lvalue.
     155                        // xxx -- old code actually removed lvalue too...
     156                        ast::ptr< ast::Type > guard = addCast;  // prevent castType from mutating addCast
     157                        ast::ptr< ast::Type > castType = addCast;
     158                        ast::remove_qualifiers(
     159                                castType,
     160                                ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
     161                        dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
     162                }
     163                fExpr->args.emplace_back( dstParam );
     164
     165                const ast::Stmt * listInit = srcParam.buildListInit( fExpr );
     166
     167                // fetch next set of arguments
     168                ++srcParam;
     169
     170                // return if adding reference fails -- will happen on default ctor and dtor
     171                if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit;
     172
     173                std::vector< ast::ptr< ast::Expr > > args = *srcParam;
     174                splice( fExpr->args, args );
     175
     176                *out++ = new ast::ExprStmt{ loc, fExpr };
     177
     178                srcParam.clearArrayIndices();
     179               
     180                return listInit;
     181        }
     182
    108183        /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
    109184        /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
    110185        template< typename OutputIterator >
    111         void genArrayCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {
     186        void genArrayCall( InitTweak::InitExpander_old & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {
    112187                static UniqueName indexName( "_index" );
    113188
     
    170245        }
    171246
     247        /// Store in out a loop which calls fname on each element of the array with srcParam and
     248        /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
     249        template< typename OutIter >
     250        void genArrayCall(
     251                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     252                const CodeLocation & loc, const std::string & fname, OutIter && out,
     253                const ast::ArrayType * array, const ast::Type * addCast = nullptr,
     254                LoopDirection forward = LoopForward
     255        ) {
     256                static UniqueName indexName( "_index" );
     257
     258                // for a flexible array member nothing is done -- user must define own assignment
     259                if ( ! array->dimension ) return;
     260
     261                if ( addCast ) {
     262                        // peel off array layer from cast
     263                        addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base;
     264                }
     265
     266                ast::ptr< ast::Expr > begin, end, cmp, update;
     267
     268                if ( forward ) {
     269                        // generate: for ( int i = 0; i < N; ++i )
     270                        begin = ast::ConstantExpr::from_int( loc, 0 );
     271                        end = array->dimension;
     272                        cmp = new ast::NameExpr{ loc, "?<?" };
     273                        update = new ast::NameExpr{ loc, "++?" };
     274                } else {
     275                        // generate: for ( int i = N-1; i >= 0; --i )
     276                        begin = new ast::UntypedExpr{
     277                                loc, new ast::NameExpr{ loc, "?-?" },
     278                                { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } };
     279                        end = ast::ConstantExpr::from_int( loc, 0 );
     280                        cmp = new ast::NameExpr{ loc, "?>=?" };
     281                        update = new ast::NameExpr{ loc, "--?" };
     282                }
     283
     284                ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{
     285                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
     286                        new ast::SingleInit{ loc, begin } };
     287               
     288                ast::ptr< ast::Expr > cond = new ast::UntypedExpr{
     289                        loc, cmp, { new ast::VariableExpr{ loc, index }, end } };
     290               
     291                ast::ptr< ast::Expr > inc = new ast::UntypedExpr{
     292                        loc, update, { new ast::VariableExpr{ loc, index } } };
     293               
     294                ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{
     295                        loc, new ast::NameExpr{ loc, "?[?]" },
     296                        { dstParam, new ast::VariableExpr{ loc, index } } };
     297               
     298                // srcParam must keep track of the array indices to build the source parameter and/or
     299                // array list initializer
     300                srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );
     301
     302                // for stmt's body, eventually containing call
     303                ast::CompoundStmt * body = new ast::CompoundStmt{ loc };
     304                ast::ptr< ast::Stmt > listInit = genCall(
     305                        srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,
     306                        forward );
     307               
     308                // block containing the stmt and index variable
     309                ast::CompoundStmt * block = new ast::CompoundStmt{ loc };
     310                block->push_back( new ast::DeclStmt{ loc, index } );
     311                if ( listInit ) { block->push_back( listInit ); }
     312                block->push_back( new ast::ForStmt{ loc, {}, cond, inc, body } );
     313
     314                *out++ = block;
     315        }
     316
    172317        template< typename OutputIterator >
    173         Statement * genCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
     318        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
    174319                if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
    175320                        genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
     
    180325        }
    181326
     327        template< typename OutIter >
     328        ast::ptr< ast::Stmt > genCall(
     329                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     330                const CodeLocation & loc, const std::string & fname, OutIter && out,
     331                const ast::Type * type, const ast::Type * addCast, LoopDirection forward
     332        ) {
     333                if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
     334                        genArrayCall(
     335                                srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
     336                                forward );
     337                        return {};
     338                } else {
     339                        return genScalarCall(
     340                                srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
     341                }
     342        }
     343
    182344        /// inserts into out a generated call expression to function fname with arguments dstParam
    183345        /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the
     
    185347        /// ImplicitCtorDtorStmt node.
    186348        template< typename OutputIterator >
    187         void genImplicitCall( InitTweak::InitExpander & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
     349        void genImplicitCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
    188350                ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl );
    189351                assert( obj );
     
    213375                }
    214376        }
     377
     378        static inline ast::ptr< ast::Stmt > genImplicitCall(
     379                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
     380                const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
     381                LoopDirection forward = LoopForward
     382        ) {
     383                // unnamed bit fields are not copied as they cannot be accessed
     384                if ( isUnnamedBitfield( obj ) ) return {};
     385
     386                ast::ptr< ast::Type > addCast = nullptr;
     387                if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
     388                        assert( dstParam->result );
     389                        addCast = dstParam->result;
     390                }
     391
     392                std::vector< ast::ptr< ast::Stmt > > stmts;
     393                genCall(
     394                        srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
     395
     396                if ( stmts.empty() ) {
     397                        return {};
     398                } else if ( stmts.size() == 1 ) {
     399                        const ast::Stmt * callStmt = stmts.front();
     400                        if ( addCast ) {
     401                                // implicitly generated ctor/dtor calls should be wrapped so that later passes are
     402                                // aware they were generated.
     403                                callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt };
     404                        }
     405                        return callStmt;
     406                } else {
     407                        assert( false );
     408                        return {};
     409                }
     410        }
    215411} // namespace SymTab
    216412
  • src/SymTab/FixFunction.cc

    r3c6e417 r54dd994  
    1818#include <list>                   // for list
    1919
    20 #include "Common/utility.h"       // for maybeClone
     20#include "AST/Decl.hpp"
     21#include "AST/Pass.hpp"
     22#include "AST/Type.hpp"
     23#include "Common/utility.h"       // for maybeClone, copy
    2124#include "SynTree/Declaration.h"  // for FunctionDecl, ObjectDecl, Declarati...
    2225#include "SynTree/Expression.h"   // for Expression
     
    2427
    2528namespace SymTab {
    26         FixFunction::FixFunction() : isVoid( false ) {}
     29        class FixFunction_old : public WithShortCircuiting {
     30                typedef Mutator Parent;
     31          public:
     32                FixFunction_old() : isVoid( false ) {}
    2733
     34                void premutate(FunctionDecl *functionDecl);
     35                DeclarationWithType* postmutate(FunctionDecl *functionDecl);
    2836
    29         DeclarationWithType * FixFunction::postmutate(FunctionDecl *functionDecl) {
     37                Type * postmutate(ArrayType * arrayType);
     38
     39                void premutate(ArrayType * arrayType);
     40                void premutate(VoidType * voidType);
     41                void premutate(BasicType * basicType);
     42                void premutate(PointerType * pointerType);
     43                void premutate(StructInstType * aggregateUseType);
     44                void premutate(UnionInstType * aggregateUseType);
     45                void premutate(EnumInstType * aggregateUseType);
     46                void premutate(TraitInstType * aggregateUseType);
     47                void premutate(TypeInstType * aggregateUseType);
     48                void premutate(TupleType * tupleType);
     49                void premutate(VarArgsType * varArgsType);
     50                void premutate(ZeroType * zeroType);
     51                void premutate(OneType * oneType);
     52
     53                bool isVoid;
     54        };
     55
     56        DeclarationWithType * FixFunction_old::postmutate(FunctionDecl *functionDecl) {
    3057                // can't delete function type because it may contain assertions, so transfer ownership to new object
    3158                ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes );
     
    4168        // does not cause an error
    4269
    43         Type * FixFunction::postmutate(ArrayType *arrayType) {
     70        Type * FixFunction_old::postmutate(ArrayType *arrayType) {
    4471                // need to recursively mutate the base type in order for multi-dimensional arrays to work.
    4572                PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic );
     
    5178        }
    5279
    53         void FixFunction::premutate(VoidType *) {
     80        void FixFunction_old::premutate(VoidType *) {
    5481                isVoid = true;
    5582        }
    5683
    57         void FixFunction::premutate(FunctionDecl *) { visit_children = false; }
    58         void FixFunction::premutate(ArrayType *) { visit_children = false; }
    59         void FixFunction::premutate(BasicType *) { visit_children = false; }
    60         void FixFunction::premutate(PointerType *) { visit_children = false; }
    61         void FixFunction::premutate(StructInstType *) { visit_children = false; }
    62         void FixFunction::premutate(UnionInstType *) { visit_children = false; }
    63         void FixFunction::premutate(EnumInstType *) { visit_children = false; }
    64         void FixFunction::premutate(TraitInstType *) { visit_children = false; }
    65         void FixFunction::premutate(TypeInstType *) { visit_children = false; }
    66         void FixFunction::premutate(TupleType *) { visit_children = false; }
    67         void FixFunction::premutate(VarArgsType *) { visit_children = false; }
    68         void FixFunction::premutate(ZeroType *) { visit_children = false; }
    69         void FixFunction::premutate(OneType *) { visit_children = false; }
     84        void FixFunction_old::premutate(FunctionDecl *) { visit_children = false; }
     85        void FixFunction_old::premutate(ArrayType *) { visit_children = false; }
     86        void FixFunction_old::premutate(BasicType *) { visit_children = false; }
     87        void FixFunction_old::premutate(PointerType *) { visit_children = false; }
     88        void FixFunction_old::premutate(StructInstType *) { visit_children = false; }
     89        void FixFunction_old::premutate(UnionInstType *) { visit_children = false; }
     90        void FixFunction_old::premutate(EnumInstType *) { visit_children = false; }
     91        void FixFunction_old::premutate(TraitInstType *) { visit_children = false; }
     92        void FixFunction_old::premutate(TypeInstType *) { visit_children = false; }
     93        void FixFunction_old::premutate(TupleType *) { visit_children = false; }
     94        void FixFunction_old::premutate(VarArgsType *) { visit_children = false; }
     95        void FixFunction_old::premutate(ZeroType *) { visit_children = false; }
     96        void FixFunction_old::premutate(OneType *) { visit_children = false; }
    7097
    7198        bool fixFunction( DeclarationWithType *& dwt ) {
    72                 PassVisitor<FixFunction> fixer;
     99                PassVisitor<FixFunction_old> fixer;
    73100                dwt = dwt->acceptMutator( fixer );
    74101                return fixer.pass.isVoid;
    75102        }
     103
     104namespace {
     105        struct FixFunction_new final : public ast::WithShortCircuiting {
     106                bool isVoid = false;
     107
     108                void premutate( const ast::FunctionDecl * ) { visit_children = false; }
     109
     110                const ast::DeclWithType * postmutate( const ast::FunctionDecl * func ) {
     111                        return new ast::ObjectDecl{
     112                                func->location, func->name, new ast::PointerType{ func->type }, nullptr,
     113                                func->storage, func->linkage, nullptr, copy( func->attributes ) };
     114                }
     115
     116                void premutate( const ast::ArrayType * ) { visit_children = false; }
     117
     118                const ast::Type * postmutate( const ast::ArrayType * array ) {
     119                        return new ast::PointerType{
     120                                array->base, array->dimension, array->isVarLen, array->isStatic,
     121                                array->qualifiers };
     122                }
     123
     124                void premutate( const ast::VoidType * ) { isVoid = true; }
     125
     126                void premutate( const ast::BasicType * ) { visit_children = false; }
     127                void premutate( const ast::PointerType * ) { visit_children = false; }
     128                void premutate( const ast::StructInstType * ) { visit_children = false; }
     129                void premutate( const ast::UnionInstType * ) { visit_children = false; }
     130                void premutate( const ast::EnumInstType * ) { visit_children = false; }
     131                void premutate( const ast::TraitInstType * ) { visit_children = false; }
     132                void premutate( const ast::TypeInstType * ) { visit_children = false; }
     133                void premutate( const ast::TupleType * ) { visit_children = false; }
     134                void premutate( const ast::VarArgsType * ) { visit_children = false; }
     135                void premutate( const ast::ZeroType * ) { visit_children = false; }
     136                void premutate( const ast::OneType * ) { visit_children = false; }
     137        };
     138} // anonymous namespace
     139
     140const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ) {
     141        ast::Pass< FixFunction_new > fixer;
     142        dwt = dwt->accept( fixer );
     143        isVoid |= fixer.pass.isVoid;
     144        return dwt;
     145}
     146
    76147} // namespace SymTab
    77148
  • src/SymTab/FixFunction.h

    r3c6e417 r54dd994  
    1919#include "SynTree/SynTree.h"    // for Types
    2020
     21namespace ast {
     22        class DeclWithType;
     23}
     24
    2125namespace SymTab {
    22         /// Replaces function and array types by equivalent pointer types.
    23         class FixFunction : public WithShortCircuiting {
    24                 typedef Mutator Parent;
    25           public:
    26                 FixFunction();
     26        /// Replaces function and array types by equivalent pointer types. Returns true if type is
     27        /// void
     28        bool fixFunction( DeclarationWithType *& );
    2729
    28                 void premutate(FunctionDecl *functionDecl);
    29                 DeclarationWithType* postmutate(FunctionDecl *functionDecl);
    30 
    31                 Type * postmutate(ArrayType * arrayType);
    32 
    33                 void premutate(ArrayType * arrayType);
    34                 void premutate(VoidType * voidType);
    35                 void premutate(BasicType * basicType);
    36                 void premutate(PointerType * pointerType);
    37                 void premutate(StructInstType * aggregateUseType);
    38                 void premutate(UnionInstType * aggregateUseType);
    39                 void premutate(EnumInstType * aggregateUseType);
    40                 void premutate(TraitInstType * aggregateUseType);
    41                 void premutate(TypeInstType * aggregateUseType);
    42                 void premutate(TupleType * tupleType);
    43                 void premutate(VarArgsType * varArgsType);
    44                 void premutate(ZeroType * zeroType);
    45                 void premutate(OneType * oneType);
    46 
    47                 bool isVoid;
    48         };
    49 
    50         bool fixFunction( DeclarationWithType *& );
     30        /// Returns declaration with function and array types replaced by equivalent pointer types.
     31        /// Sets isVoid to true if type is void
     32        const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid );
    5133} // namespace SymTab
    5234
  • src/SymTab/Validate.cc

    r3c6e417 r54dd994  
    4646#include <utility>                     // for pair
    4747
     48#include "AST/Decl.hpp"
     49#include "AST/Node.hpp"
     50#include "AST/Pass.hpp"
     51#include "AST/SymbolTable.hpp"
     52#include "AST/Type.hpp"
    4853#include "CodeGen/CodeGenerator.h"     // for genName
    4954#include "CodeGen/OperatorTable.h"     // for isCtorDtor, isCtorDtorAssign
     
    124129
    125130        /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers.
    126         struct EnumAndPointerDecay {
     131        struct EnumAndPointerDecay_old {
    127132                void previsit( EnumDecl *aggregateDecl );
    128133                void previsit( FunctionType *func );
     
    130135
    131136        /// Associates forward declarations of aggregates with their definitions
    132         struct LinkReferenceToTypes final : public WithIndexer, public WithGuards, public WithVisitorRef<LinkReferenceToTypes>, public WithShortCircuiting {
    133                 LinkReferenceToTypes( const Indexer *indexer );
     137        struct LinkReferenceToTypes_old final : public WithIndexer, public WithGuards, public WithVisitorRef<LinkReferenceToTypes_old>, public WithShortCircuiting {
     138                LinkReferenceToTypes_old( const Indexer *indexer );
    134139                void postvisit( TypeInstType *typeInst );
    135140
     
    165170
    166171        /// Replaces array and function types in forall lists by appropriate pointer type and assigns each Object and Function declaration a unique ID.
    167         struct ForallPointerDecay final {
     172        struct ForallPointerDecay_old final {
    168173                void previsit( ObjectDecl * object );
    169174                void previsit( FunctionDecl * func );
     
    290295
    291296        void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) {
    292                 PassVisitor<EnumAndPointerDecay> epc;
    293                 PassVisitor<LinkReferenceToTypes> lrt( nullptr );
    294                 PassVisitor<ForallPointerDecay> fpd;
     297                PassVisitor<EnumAndPointerDecay_old> epc;
     298                PassVisitor<LinkReferenceToTypes_old> lrt( nullptr );
     299                PassVisitor<ForallPointerDecay_old> fpd;
    295300                PassVisitor<CompoundLiteral> compoundliteral;
    296301                PassVisitor<ValidateGenericParameters> genericParams;
     
    305310                        ReplaceTypedef::replaceTypedef( translationUnit );
    306311                        ReturnTypeFixer::fix( translationUnit ); // must happen before autogen
    307                         acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes because it is an indexer and needs correct types for mangling
     312                        acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling
    308313                }
    309314                {
     
    314319                        });
    315320                        Stats::Time::TimeBlock("Fix Qualified Types", [&]() {
    316                                 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes, because aggregate members are accessed
     321                                mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes_old, because aggregate members are accessed
    317322                        });
    318323                        Stats::Time::TimeBlock("Hoist Structs", [&]() {
     
    326331                        Stats::Heap::newPass("validate-C");
    327332                        Stats::Time::BlockGuard guard("validate-C");
    328                         acceptAll( translationUnit, genericParams );  // check as early as possible - can't happen before LinkReferenceToTypes
     333                        acceptAll( translationUnit, genericParams );  // check as early as possible - can't happen before LinkReferenceToTypes_old
    329334                        VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
    330335                        ReturnChecker::checkFunctionReturns( translationUnit );
     
    344349                        });
    345350                        Stats::Time::TimeBlock("Generate Autogen routines", [&]() {
    346                                 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay
     351                                autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay_old
    347352                        });
    348353                }
     
    385390
    386391        void validateType( Type *type, const Indexer *indexer ) {
    387                 PassVisitor<EnumAndPointerDecay> epc;
    388                 PassVisitor<LinkReferenceToTypes> lrt( indexer );
    389                 PassVisitor<ForallPointerDecay> fpd;
     392                PassVisitor<EnumAndPointerDecay_old> epc;
     393                PassVisitor<LinkReferenceToTypes_old> lrt( indexer );
     394                PassVisitor<ForallPointerDecay_old> fpd;
    390395                type->accept( epc );
    391396                type->accept( lrt );
     
    586591        }
    587592
    588         void EnumAndPointerDecay::previsit( EnumDecl *enumDecl ) {
     593        void EnumAndPointerDecay_old::previsit( EnumDecl *enumDecl ) {
    589594                // Set the type of each member of the enumeration to be EnumConstant
    590595                for ( std::list< Declaration * >::iterator i = enumDecl->members.begin(); i != enumDecl->members.end(); ++i ) {
     
    618623        }
    619624
    620         void EnumAndPointerDecay::previsit( FunctionType *func ) {
     625        void EnumAndPointerDecay_old::previsit( FunctionType *func ) {
    621626                // Fix up parameters and return types
    622627                fixFunctionList( func->parameters, func->isVarArgs, func );
     
    624629        }
    625630
    626         LinkReferenceToTypes::LinkReferenceToTypes( const Indexer *other_indexer ) {
     631        LinkReferenceToTypes_old::LinkReferenceToTypes_old( const Indexer *other_indexer ) {
    627632                if ( other_indexer ) {
    628633                        local_indexer = other_indexer;
     
    632637        }
    633638
    634         void LinkReferenceToTypes::postvisit( EnumInstType *enumInst ) {
     639        void LinkReferenceToTypes_old::postvisit( EnumInstType *enumInst ) {
    635640                EnumDecl *st = local_indexer->lookupEnum( enumInst->name );
    636641                // it's not a semantic error if the enum is not found, just an implicit forward declaration
     
    652657        }
    653658
    654         void LinkReferenceToTypes::postvisit( StructInstType *structInst ) {
     659        void LinkReferenceToTypes_old::postvisit( StructInstType *structInst ) {
    655660                StructDecl *st = local_indexer->lookupStruct( structInst->name );
    656661                // it's not a semantic error if the struct is not found, just an implicit forward declaration
     
    665670        }
    666671
    667         void LinkReferenceToTypes::postvisit( UnionInstType *unionInst ) {
     672        void LinkReferenceToTypes_old::postvisit( UnionInstType *unionInst ) {
    668673                UnionDecl *un = local_indexer->lookupUnion( unionInst->name );
    669674                // it's not a semantic error if the union is not found, just an implicit forward declaration
     
    678683        }
    679684
    680         void LinkReferenceToTypes::previsit( QualifiedType * ) {
     685        void LinkReferenceToTypes_old::previsit( QualifiedType * ) {
    681686                visit_children = false;
    682687        }
    683688
    684         void LinkReferenceToTypes::postvisit( QualifiedType * qualType ) {
     689        void LinkReferenceToTypes_old::postvisit( QualifiedType * qualType ) {
    685690                // linking only makes sense for the 'oldest ancestor' of the qualified type
    686691                qualType->parent->accept( *visitor );
     
    729734        }
    730735
    731         void LinkReferenceToTypes::postvisit( TraitDecl * traitDecl ) {
     736        void LinkReferenceToTypes_old::postvisit( TraitDecl * traitDecl ) {
    732737                if ( traitDecl->name == "sized" ) {
    733738                        // "sized" is a special trait - flick the sized status on for the type variable
     
    751756        }
    752757
    753         void LinkReferenceToTypes::postvisit( TraitInstType * traitInst ) {
     758        void LinkReferenceToTypes_old::postvisit( TraitInstType * traitInst ) {
    754759                // handle other traits
    755760                TraitDecl *traitDecl = local_indexer->lookupTrait( traitInst->name );
     
    777782        }
    778783
    779         void LinkReferenceToTypes::postvisit( EnumDecl *enumDecl ) {
     784        void LinkReferenceToTypes_old::postvisit( EnumDecl *enumDecl ) {
    780785                // visit enum members first so that the types of self-referencing members are updated properly
    781786                if ( enumDecl->body ) {
     
    799804        }
    800805
    801         void LinkReferenceToTypes::renameGenericParams( std::list< TypeDecl * > & params ) {
     806        void LinkReferenceToTypes_old::renameGenericParams( std::list< TypeDecl * > & params ) {
    802807                // rename generic type parameters uniquely so that they do not conflict with user-defined function forall parameters, e.g.
    803808                //   forall(otype T)
     
    817822        }
    818823
    819         void LinkReferenceToTypes::previsit( StructDecl * structDecl ) {
     824        void LinkReferenceToTypes_old::previsit( StructDecl * structDecl ) {
    820825                renameGenericParams( structDecl->parameters );
    821826        }
    822827
    823         void LinkReferenceToTypes::previsit( UnionDecl * unionDecl ) {
     828        void LinkReferenceToTypes_old::previsit( UnionDecl * unionDecl ) {
    824829                renameGenericParams( unionDecl->parameters );
    825830        }
    826831
    827         void LinkReferenceToTypes::postvisit( StructDecl *structDecl ) {
     832        void LinkReferenceToTypes_old::postvisit( StructDecl *structDecl ) {
    828833                // visit struct members first so that the types of self-referencing members are updated properly
    829834                // xxx - need to ensure that type parameters match up between forward declarations and definition (most importantly, number of type parameters and their defaults)
     
    839844        }
    840845
    841         void LinkReferenceToTypes::postvisit( UnionDecl *unionDecl ) {
     846        void LinkReferenceToTypes_old::postvisit( UnionDecl *unionDecl ) {
    842847                if ( unionDecl->body ) {
    843848                        ForwardUnionsType::iterator fwds = forwardUnions.find( unionDecl->name );
     
    851856        }
    852857
    853         void LinkReferenceToTypes::postvisit( TypeInstType *typeInst ) {
     858        void LinkReferenceToTypes_old::postvisit( TypeInstType *typeInst ) {
    854859                // ensure generic parameter instances are renamed like the base type
    855860                if ( inGeneric && typeInst->baseType ) typeInst->name = typeInst->baseType->name;
     
    888893        }
    889894
    890         void ForallPointerDecay::previsit( ObjectDecl *object ) {
     895        void ForallPointerDecay_old::previsit( ObjectDecl *object ) {
    891896                // ensure that operator names only apply to functions or function pointers
    892897                if ( CodeGen::isOperator( object->name ) && ! dynamic_cast< FunctionType * >( object->type->stripDeclarator() ) ) {
     
    896901        }
    897902
    898         void ForallPointerDecay::previsit( FunctionDecl *func ) {
     903        void ForallPointerDecay_old::previsit( FunctionDecl *func ) {
    899904                func->fixUniqueId();
    900905        }
    901906
    902         void ForallPointerDecay::previsit( FunctionType * ftype ) {
     907        void ForallPointerDecay_old::previsit( FunctionType * ftype ) {
    903908                forallFixer( ftype->forall, ftype );
    904909        }
    905910
    906         void ForallPointerDecay::previsit( StructDecl * aggrDecl ) {
     911        void ForallPointerDecay_old::previsit( StructDecl * aggrDecl ) {
    907912                forallFixer( aggrDecl->parameters, aggrDecl );
    908913        }
    909914
    910         void ForallPointerDecay::previsit( UnionDecl * aggrDecl ) {
     915        void ForallPointerDecay_old::previsit( UnionDecl * aggrDecl ) {
    911916                forallFixer( aggrDecl->parameters, aggrDecl );
    912917        }
     
    13681373        }
    13691374
    1370         const ast::Type * validateType( const ast::Type * type, const ast::SymbolTable & symtab ) {
    1371                 #warning unimplemented
    1372                 (void)type; (void)symtab;
    1373                 assert(false);
    1374                 return nullptr;
    1375         }
     1375namespace {
     1376        /// Replaces enum types by int, and function/array types in function parameter and return
     1377        /// lists by appropriate pointers
     1378        struct EnumAndPointerDecay_new {
     1379                const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) {
     1380                        // set the type of each member of the enumeration to be EnumConstant
     1381                        for ( unsigned i = 0; i < enumDecl->members.size(); ++i ) {
     1382                                // build new version of object with EnumConstant
     1383                                ast::ptr< ast::ObjectDecl > obj =
     1384                                        enumDecl->members[i].strict_as< ast::ObjectDecl >();
     1385                                obj.get_and_mutate()->type =
     1386                                        new ast::EnumInstType{ enumDecl->name, ast::CV::Const };
     1387                               
     1388                                // set into decl
     1389                                ast::EnumDecl * mut = mutate( enumDecl );
     1390                                mut->members[i] = obj.get();
     1391                                enumDecl = mut;
     1392                        }
     1393                        return enumDecl;
     1394                }
     1395
     1396                static const ast::FunctionType * fixFunctionList(
     1397                        const ast::FunctionType * func,
     1398                        std::vector< ast::ptr< ast::DeclWithType > > ast::FunctionType::* field,
     1399                        ast::ArgumentFlag isVarArgs = ast::FixedArgs
     1400                ) {
     1401                        const auto & dwts = func->*field;
     1402                        unsigned nvals = dwts.size();
     1403                        bool hasVoid = false;
     1404                        for ( unsigned i = 0; i < nvals; ++i ) {
     1405                                func = ast::mutate_field_index( func, field, i, fixFunction( dwts[i], hasVoid ) );
     1406                        }
     1407                       
     1408                        // the only case in which "void" is valid is where it is the only one in the list
     1409                        if ( hasVoid && ( nvals > 1 || isVarArgs ) ) {
     1410                                SemanticError(
     1411                                        dwts.front()->location, func, "invalid type void in function type" );
     1412                        }
     1413
     1414                        // one void is the only thing in the list, remove it
     1415                        if ( hasVoid ) {
     1416                                func = ast::mutate_field(
     1417                                        func, field, std::vector< ast::ptr< ast::DeclWithType > >{} );
     1418                        }
     1419
     1420                        return func;
     1421                }
     1422
     1423                const ast::FunctionType * previsit( const ast::FunctionType * func ) {
     1424                        func = fixFunctionList( func, &ast::FunctionType::params, func->isVarArgs );
     1425                        return fixFunctionList( func, &ast::FunctionType::returns );
     1426                }
     1427        };
     1428
     1429        /// Associates forward declarations of aggregates with their definitions
     1430        struct LinkReferenceToTypes_new final
     1431        : public ast::WithSymbolTable, public ast::WithGuards, public
     1432          ast::WithVisitorRef<LinkReferenceToTypes_new>, public ast::WithShortCircuiting {
     1433               
     1434                const ast::SymbolTable * localSyms;
     1435
     1436                LinkReferenceToTypes_new( const ast::SymbolTable & syms ) : localSyms( &syms ) {}
     1437
     1438                #warning incomplete
     1439        };
     1440
     1441        /// Replaces array and function types in forall lists by appropriate pointer type and assigns
     1442        /// each object and function declaration a unique ID
     1443        struct ForallPointerDecay_new {
     1444                #warning incomplete
     1445        };
     1446} // anonymous namespace
     1447
     1448const ast::Type * validateType( const ast::Type * type, const ast::SymbolTable & symtab ) {
     1449        ast::Pass< EnumAndPointerDecay_new > epc;
     1450        ast::Pass< LinkReferenceToTypes_new > lrt{ symtab };
     1451        ast::Pass< ForallPointerDecay_new > fpd;
     1452
     1453        return type->accept( epc )->accept( lrt )->accept( fpd );
     1454}
     1455
    13761456} // namespace SymTab
    13771457
  • src/Tuples/Explode.cc

    r3c6e417 r54dd994  
    133133                        if ( first ) {
    134134                                castAdded = true;
    135                                 const ast::Expr * tuple = new ast::TupleExpr(
    136                                         tupleExpr->location, std::move( exprs ) );
    137                                 return new ast::CastExpr( tuple->location,
    138                                         tuple, new ast::ReferenceType( tuple->result.get(), ast::CV::Qualifiers() ) );
     135                                const ast::Expr * tuple = new ast::TupleExpr{
     136                                        tupleExpr->location, std::move( exprs ) };
     137                                return new ast::CastExpr{ tuple, new ast::ReferenceType{ tuple->result } };
    139138                        } else {
    140139                                return new ast::TupleExpr( tupleExpr->location, std::move( exprs ) );
     
    145144                } else {
    146145                        castAdded = true;
    147                         return new ast::CastExpr( expr->location, expr,
    148                                 new ast::ReferenceType( expr->result, ast::CV::Qualifiers() ) );
     146                        return new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
    149147                }
    150148        }
     
    164162                        castAdded = false;
    165163                        const ast::Type * newType = getReferenceBase( newNode->result );
    166                         return new ast::CastExpr( newNode->location, node, newType );
     164                        return new ast::CastExpr{ newNode->location, node, newType };
    167165                }
    168166                return newNode;
     
    183181        expr = expr->accept( exploder );
    184182        if ( ! exploder.pass.foundUniqueExpr ) {
    185                 expr = new ast::CastExpr( expr->location, expr,
    186                         new ast::ReferenceType( expr->result, ast::CV::Qualifiers() ) );
     183                expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
    187184        }
    188185        return expr;
  • src/Tuples/Explode.h

    r3c6e417 r54dd994  
    211211                        // Cast a reference away to a value-type to allow further explosion.
    212212                        if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
    213                                 local = new ast::CastExpr( local->location, local, tupleType );
     213                                local = new ast::CastExpr{ local, tupleType };
    214214                        }
    215215                        // Now we have to go across the tuple via indexing.
     
    238238}
    239239
     240/// explode list of candidates into flattened list of candidates
     241template< typename Output >
     242void explode(
     243        const ResolvExpr::CandidateList & cands, const ast::SymbolTable & symtab, Output && out,
     244        bool isTupleAssign = false
     245) {
     246        for ( const ResolvExpr::CandidateRef & cand : cands ) {
     247                explode( *cand, symtab, std::forward< Output >( out ), isTupleAssign );
     248        }
     249}
     250
    240251} // namespace Tuples
    241252
  • src/Tuples/TupleAssignment.cc

    r3c6e417 r54dd994  
    2222#include <vector>
    2323
     24#include "AST/Decl.hpp"
     25#include "AST/Init.hpp"
     26#include "AST/Pass.hpp"
     27#include "AST/Stmt.hpp"
     28#include "AST/TypeEnvironment.hpp"
    2429#include "CodeGen/OperatorTable.h"
    2530#include "Common/PassVisitor.h"
    2631#include "Common/UniqueName.h"             // for UniqueName
    27 #include "Common/utility.h"                // for zipWith
     32#include "Common/utility.h"                // for splice, zipWith
    2833#include "Explode.h"                       // for explode
    2934#include "InitTweak/GenInit.h"             // for genCtorInit
     
    5156
    5257namespace Tuples {
    53         class TupleAssignSpotter {
     58        class TupleAssignSpotter_old {
    5459          public:
    5560                // dispatcher for Tuple (multiple and mass) assignment operations
    56                 TupleAssignSpotter( ResolvExpr::AlternativeFinder & );
     61                TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );
    5762                void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
    5863
     
    6267                struct Matcher {
    6368                  public:
    64                         Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     69                        Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    6570                                const ResolvExpr::AltList& rhs );
    6671                        virtual ~Matcher() {}
     
    8085                       
    8186                        ResolvExpr::AltList lhs, rhs;
    82                         TupleAssignSpotter &spotter;
     87                        TupleAssignSpotter_old &spotter;
    8388                        ResolvExpr::Cost baseCost;
    8489                        std::list< ObjectDecl * > tmpDecls;
     
    9095                struct MassAssignMatcher : public Matcher {
    9196                  public:
    92                         MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     97                        MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    9398                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    9499                        virtual void match( std::list< Expression * > &out );
     
    97102                struct MultipleAssignMatcher : public Matcher {
    98103                  public:
    99                         MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     104                        MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    100105                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    101106                        virtual void match( std::list< Expression * > &out );
     
    136141        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
    137142                                std::vector<ResolvExpr::AlternativeFinder> &args ) {
    138                 TupleAssignSpotter spotter( currentFinder );
     143                TupleAssignSpotter_old spotter( currentFinder );
    139144                spotter.spot( expr, args );
    140145        }
    141146
    142         TupleAssignSpotter::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f )
     147        TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
    143148                : currentFinder(f) {}
    144149
    145         void TupleAssignSpotter::spot( UntypedExpr * expr,
     150        void TupleAssignSpotter_old::spot( UntypedExpr * expr,
    146151                        std::vector<ResolvExpr::AlternativeFinder> &args ) {
    147152                if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
     
    224229        }
    225230
    226         void TupleAssignSpotter::match() {
     231        void TupleAssignSpotter_old::match() {
    227232                assert ( matcher != 0 );
    228233
     
    275280        }
    276281
    277         TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter,
     282        TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,
    278283                const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
    279284        : lhs(lhs), rhs(rhs), spotter(spotter),
     
    313318        };
    314319
    315         ObjectDecl * TupleAssignSpotter::Matcher::newObject( UniqueName & namer, Expression * expr ) {
     320        ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
    316321                assert( expr->result && ! expr->get_result()->isVoid() );
    317322                ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
     
    329334        }
    330335
    331         void TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) {
     336        void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
    332337                static UniqueName lhsNamer( "__massassign_L" );
    333338                static UniqueName rhsNamer( "__massassign_R" );
     
    347352        }
    348353
    349         void TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
     354        void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
    350355                static UniqueName lhsNamer( "__multassign_L" );
    351356                static UniqueName rhsNamer( "__multassign_R" );
     
    378383        }
    379384
    380         void handleTupleAssignment(
    381                 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
    382                 std::vector< ResolvExpr::CandidateFinder > & args
    383         ) {
    384                 #warning unimplmented
    385                 (void)finder; (void)assign; (void)args;
    386                 assert(false);
    387         }
     385namespace {
     386        /// true if `expr` is of tuple type
     387        bool isTuple( const ast::Expr * expr ) {
     388                if ( ! expr ) return false;
     389                assert( expr->result );
     390                return dynamic_cast< const ast::TupleType * >( expr->result->stripReferences() );
     391        }
     392       
     393        /// true if `expr` is of tuple type or a reference to one
     394        bool refToTuple( const ast::Expr * expr ) {
     395                assert( expr->result );
     396                // check for function returning tuple of reference types
     397                if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {
     398                        return refToTuple( castExpr->arg );
     399                } else {
     400                        return isTuple( expr );
     401                }
     402        }
     403
     404        /// Dispatcher for tuple (multiple and mass) assignment operations
     405        class TupleAssignSpotter_new final {
     406                /// Actually finds tuple assignment operations, by subclass
     407                struct Matcher {
     408                        ResolvExpr::CandidateList lhs, rhs;
     409                        TupleAssignSpotter_new & spotter;
     410                        CodeLocation location;
     411                        ResolvExpr::Cost baseCost;
     412                        std::vector< ast::ptr< ast::ObjectDecl > > tmpDecls;
     413                        ast::TypeEnvironment env;
     414                        ast::OpenVarSet open;
     415                        ast::AssertionSet need;
     416
     417                        void combineState( const ResolvExpr::Candidate & cand ) {
     418                                env.simpleCombine( cand.env );
     419                                ast::mergeOpenVars( open, cand.open );
     420                                need.insert( cand.need.begin(), cand.need.end() );
     421                        }
     422
     423                        Matcher(
     424                                TupleAssignSpotter_new & s, const CodeLocation & loc,
     425                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     426                        : lhs( l ), rhs( r ), spotter( s ), location( loc ),
     427                          baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(),
     428                          env(), open(), need() {
     429                                for ( auto & cand : lhs ) combineState( *cand );
     430                                for ( auto & cand : rhs ) combineState( *cand );
     431                        }
     432
     433                        virtual std::vector< ast::ptr< ast::Expr > > match() = 0;
     434
     435                        /// removes environments from subexpressions within statement expressions, which could
     436                        /// throw off later passes like those in Box which rely on PolyMutator, and adds the
     437                        /// bindings to the env
     438                        struct EnvRemover {
     439                                /// environment to hoist ExprStmt environments to
     440                                ast::TypeEnvironment & tenv;
     441
     442                                EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {}
     443
     444                                const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) {
     445                                        if ( stmt->expr->env ) {
     446                                                tenv.add( *stmt->expr->env );
     447                                                ast::ExprStmt * mut = mutate( stmt );
     448                                                mut->expr.get_and_mutate()->env = nullptr;
     449                                                return mut;
     450                                        }
     451                                        return stmt;
     452                                }
     453                        };
     454
     455                        ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) {
     456                                assert( expr->result && ! expr->result->isVoid() );
     457                               
     458                                ast::ObjectDecl * ret = new ast::ObjectDecl{
     459                                        location, namer.newName(), expr->result, new ast::SingleInit{ location, expr },
     460                                        ast::Storage::Classes{}, ast::Linkage::Cforall };
     461                               
     462                                // if expression type is a reference, just need an initializer, otherwise construct
     463                                if ( ! expr->result.as< ast::ReferenceType >() ) {
     464                                        // resolve ctor/dtor for the new object
     465                                        ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
     466                                                        InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab );
     467                                        // remove environments from subexpressions of stmtExpr
     468                                        ast::Pass< EnvRemover > rm{ env };
     469                                        ret->init = ctorInit->accept( rm );
     470                                }
     471
     472                                PRINT( std::cerr << "new object: " << ret << std::endl; )
     473                                return ret;
     474                        }
     475
     476                        ast::UntypedExpr * createFunc(
     477                                const std::string & fname, const ast::ObjectDecl * left,
     478                                const ast::ObjectDecl * right
     479                        ) {
     480                                assert( left );
     481                                std::vector< ast::ptr< ast::Expr > > args;
     482                                args.emplace_back( new ast::VariableExpr{ location, left } );
     483                                if ( right ) { args.emplace_back( new ast::VariableExpr{ location, right } ); }
     484
     485                                if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
     486                                        args.front() = new ast::AddressExpr{ location, args.front() };
     487                                        if ( right ) { args.back() = new ast::AddressExpr{ location, args.back() }; }
     488                                        return new ast::UntypedExpr{
     489                                                location, new ast::NameExpr{ location, "?=?" }, std::move(args) };
     490                                } else {
     491                                        return new ast::UntypedExpr{
     492                                                location, new ast::NameExpr{ location, fname }, std::move(args) };
     493                                }
     494                        }
     495                };
     496
     497                /// Finds mass-assignment operations
     498                struct MassAssignMatcher final : public Matcher {
     499                        MassAssignMatcher(
     500                                TupleAssignSpotter_new & s, const CodeLocation & loc,
     501                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     502                        : Matcher( s, loc, l, r ) {}
     503
     504                        std::vector< ast::ptr< ast::Expr > > match() override {
     505                                static UniqueName lhsNamer( "__massassign_L" );
     506                                static UniqueName rhsNamer( "__massassign_R" );
     507                                // empty tuple case falls into this matcher
     508                                assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
     509
     510                                ast::ptr< ast::ObjectDecl > rtmp =
     511                                        rhs.size() == 1 ? newObject( rhsNamer, rhs.front()->expr ) : nullptr;
     512
     513                                std::vector< ast::ptr< ast::Expr > > out;
     514                                for ( ResolvExpr::CandidateRef & lhsCand : lhs ) {
     515                                        // create a temporary object for each value in the LHS and create a call
     516                                        // involving the RHS
     517                                        ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr );
     518                                        out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) );
     519                                        tmpDecls.emplace_back( std::move( ltmp ) );
     520                                }
     521                                if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) );
     522
     523                                return out;
     524                        }
     525                };
     526
     527                /// Finds multiple-assignment operations
     528                struct MultipleAssignMatcher final : public Matcher {
     529                        MultipleAssignMatcher(
     530                                TupleAssignSpotter_new & s, const CodeLocation & loc,
     531                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     532                        : Matcher( s, loc, l, r ) {}
     533
     534                        std::vector< ast::ptr< ast::Expr > > match() override {
     535                                static UniqueName lhsNamer( "__multassign_L" );
     536                                static UniqueName rhsNamer( "__multassign_R" );
     537
     538                                if ( lhs.size() != rhs.size() ) return {};
     539
     540                                // produce a new temporary object for each value in the LHS and RHS and pairwise
     541                                // create the calls
     542                                std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp;
     543
     544                                std::vector< ast::ptr< ast::Expr > > out;
     545                                for ( unsigned i = 0; i < lhs.size(); ++i ) {
     546                                        ResolvExpr::CandidateRef & lhsCand = lhs[i];
     547                                        ResolvExpr::CandidateRef & rhsCand = rhs[i];
     548
     549                                        // convert RHS to LHS type minus one reference -- important for case where LHS
     550                                        // is && and RHS is lvalue
     551                                        auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >();
     552                                        rhsCand->expr = new ast::CastExpr{ rhsCand->expr, lhsType->base };
     553                                        ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr );
     554                                        ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr );
     555                                        out.emplace_back( createFunc( spotter.fname, lobj, robj ) );
     556                                        ltmp.emplace_back( std::move( lobj ) );
     557                                        rtmp.emplace_back( std::move( robj ) );
     558
     559                                        // resolve the cast expression so that rhsCand return type is bound by the cast
     560                                        // type as needed, and transfer the resulting environment
     561                                        ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env };
     562                                        finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
     563                                        assert( finder.candidates.size() == 1 );
     564                                        env = std::move( finder.candidates.front()->env );
     565                                }
     566                               
     567                                splice( tmpDecls, ltmp );
     568                                splice( tmpDecls, rtmp );
     569                               
     570                                return out;
     571                        }
     572                };
     573
     574                ResolvExpr::CandidateFinder & crntFinder;
     575                std::string fname;
     576                std::unique_ptr< Matcher > matcher;
     577       
     578        public:
     579                TupleAssignSpotter_new( ResolvExpr::CandidateFinder & f )
     580                : crntFinder( f ), fname(), matcher() {}
     581
     582                // find left- and right-hand-sides for mass or multiple assignment
     583                void spot(
     584                        const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args
     585                ) {
     586                        if ( auto op = expr->func.as< ast::NameExpr >() ) {
     587                                // skip non-assignment functions
     588                                if ( ! CodeGen::isCtorDtorAssign( op->name ) ) return;
     589                                fname = op->name;
     590
     591                                // handled by CandidateFinder if applicable (both odd cases)
     592                                if ( args.empty() || ( args.size() == 1 && CodeGen::isAssignment( fname ) ) ) {
     593                                        return;
     594                                }
     595
     596                                // look over all possible left-hand-side
     597                                for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) {
     598                                        // skip non-tuple LHS
     599                                        if ( ! refToTuple( lhsCand->expr ) ) continue;
     600
     601                                        // explode is aware of casts - ensure every LHS is sent into explode with a
     602                                        // reference cast
     603                                        if ( ! lhsCand->expr.as< ast::CastExpr >() ) {
     604                                                lhsCand->expr = new ast::CastExpr{
     605                                                        lhsCand->expr, new ast::ReferenceType{ lhsCand->expr->result } };
     606                                        }
     607
     608                                        // explode the LHS so that each field of a tuple-valued expr is assigned
     609                                        ResolvExpr::CandidateList lhs;
     610                                        explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
     611                                        for ( ResolvExpr::CandidateRef & cand : lhs ) {
     612                                                // each LHS value must be a reference - some come in with a cast, if not
     613                                                // just cast to reference here
     614                                                if ( ! cand->expr->result.as< ast::ReferenceType >() ) {
     615                                                        cand->expr = new ast::CastExpr{
     616                                                                cand->expr, new ast::ReferenceType{ cand->expr->result } };
     617                                                }
     618                                        }
     619
     620                                        if ( args.size() == 1 ) {
     621                                                // mass default-initialization/destruction
     622                                                ResolvExpr::CandidateList rhs{};
     623                                                matcher.reset( new MassAssignMatcher{ *this, expr->location, lhs, rhs } );
     624                                                match();
     625                                        } else if ( args.size() == 2 ) {
     626                                                for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) {
     627                                                        ResolvExpr::CandidateList rhs;
     628                                                        if ( isTuple( rhsCand->expr ) ) {
     629                                                                // multiple assignment
     630                                                                explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     631                                                                matcher.reset(
     632                                                                        new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     633                                                        } else {
     634                                                                // mass assignment
     635                                                                rhs.emplace_back( rhsCand );
     636                                                                matcher.reset(
     637                                                                        new MassAssignMatcher{ *this, expr->location, lhs, rhs } );
     638                                                        }
     639                                                        match();
     640                                                }
     641                                        } else {
     642                                                // expand all possible RHS possibilities
     643                                                std::vector< ResolvExpr::CandidateList > rhsCands;
     644                                                combos(
     645                                                        std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) );
     646                                                for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) {
     647                                                        // multiple assignment
     648                                                        ResolvExpr::CandidateList rhs;
     649                                                        explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     650                                                        matcher.reset(
     651                                                                new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     652                                                        match();
     653                                                }
     654                                        }
     655                                }
     656                        }
     657                }
     658
     659                void match() {
     660                        assert( matcher );
     661
     662                        std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match();
     663
     664                        if ( ! ( matcher->lhs.empty() && matcher->rhs.empty() ) ) {
     665                                // if both LHS and RHS are empty than this is the empty tuple case, wherein it's
     666                                // okay for newAssigns to be empty. Otherwise, return early so that no new
     667                                // candidates are generated
     668                                if ( newAssigns.empty() ) return;
     669                        }
     670
     671                        ResolvExpr::CandidateList crnt;
     672                        // now resolve new assignments
     673                        for ( const ast::Expr * expr : newAssigns ) {
     674                                PRINT(
     675                                        std::cerr << "== resolving tuple assign ==" << std::endl;
     676                                        std::cerr << expr << std::endl;
     677                                )
     678
     679                                ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
     680
     681                                try {
     682                                        finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() );
     683                                } catch (...) {
     684                                        // no match is not failure, just that this tuple assignment is invalid
     685                                        return;
     686                                }
     687
     688                                ResolvExpr::CandidateList & cands = finder.candidates;
     689                                assert( cands.size() == 1 );
     690                                assert( cands.front()->expr );
     691                                crnt.emplace_back( std::move( cands.front() ) );
     692                        }
     693
     694                        // extract expressions from the assignment candidates to produce a list of assignments
     695                        // that together form a sigle candidate
     696                        std::vector< ast::ptr< ast::Expr > > solved;
     697                        for ( ResolvExpr::CandidateRef & cand : crnt ) {
     698                                solved.emplace_back( cand->expr );
     699                                matcher->combineState( *cand );
     700                        }
     701
     702                        crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >(
     703                                new ast::TupleAssignExpr{
     704                                        matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) },
     705                                std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ),
     706                                ResolvExpr::sumCost( crnt ) + matcher->baseCost ) );
     707                }
     708        };
     709} // anonymous namespace
     710
     711void handleTupleAssignment(
     712        ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     713        std::vector< ResolvExpr::CandidateFinder > & args
     714) {
     715        TupleAssignSpotter_new spotter{ finder };
     716        spotter.spot( assign, args );
     717}
     718
    388719} // namespace Tuples
    389720
Note: See TracChangeset for help on using the changeset viewer.