Changeset fc12f05 for src


Ignore:
Timestamp:
Nov 13, 2023, 3:43:43 AM (2 years ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
25f2798
Parents:
0030b508 (diff), 2174191 (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:
2 added
114 deleted
103 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Decl.hpp

    r0030b508 rfc12f05  
    125125
    126126/// Object declaration `int foo()`
    127 class FunctionDecl : public DeclWithType {
     127class FunctionDecl final : public DeclWithType {
    128128public:
    129129        std::vector<ptr<TypeDecl>> type_params;
     
    314314class EnumDecl final : public AggregateDecl {
    315315public:
    316         bool isTyped; // isTyped indicated if the enum has a declaration like:
     316        // isTyped indicated if the enum has a declaration like:
    317317        // enum (type_optional) Name {...}
    318         ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
     318        bool isTyped;
     319        // if isTyped == true && base.get() == nullptr, it is a "void" type enum
     320        ptr<Type> base;
    319321        enum class EnumHiding { Visible, Hide } hide;
    320322
     
    374376
    375377/// Assembly declaration: `asm ... ( "..." : ... )`
    376 class AsmDecl : public Decl {
     378class AsmDecl final : public Decl {
    377379public:
    378380        ptr<AsmStmt> stmt;
    379381
    380382        AsmDecl( const CodeLocation & loc, AsmStmt * stmt )
    381         : Decl( loc, "", {}, {} ), stmt(stmt) {}
     383        : Decl( loc, "", {}, Linkage::C ), stmt(stmt) {}
    382384
    383385        const AsmDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     
    388390
    389391/// C-preprocessor directive `#...`
    390 class DirectiveDecl : public Decl {
     392class DirectiveDecl final : public Decl {
    391393public:
    392394        ptr<DirectiveStmt> stmt;
    393395
    394396        DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt )
    395         : Decl( loc, "", {}, {} ), stmt(stmt) {}
     397        : Decl( loc, "", {}, Linkage::C ), stmt(stmt) {}
    396398
    397399        const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     
    402404
    403405/// Static Assertion `_Static_assert( ... , ... );`
    404 class StaticAssertDecl : public Decl {
     406class StaticAssertDecl final : public Decl {
    405407public:
    406408        ptr<Expr> cond;
     
    408410
    409411        StaticAssertDecl( const CodeLocation & loc, const Expr * condition, const ConstantExpr * msg )
    410         : Decl( loc, "", {}, {} ), cond( condition ), msg( msg ) {}
     412        : Decl( loc, "", {}, Linkage::C ), cond( condition ), msg( msg ) {}
    411413
    412414        const StaticAssertDecl * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

    r0030b508 rfc12f05  
    6868class MutexStmt;
    6969class CorunStmt;
     70class CoforStmt;
    7071
    7172class Expr;
  • src/AST/Node.cpp

    r0030b508 rfc12f05  
    194194template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::weak >;
    195195template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::strong >;
     196template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::weak >;
     197template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::strong >;
    196198template class ast::ptr_base< ast::Expr, ast::Node::ref_type::weak >;
    197199template class ast::ptr_base< ast::Expr, ast::Node::ref_type::strong >;
  • src/AST/Pass.cpp

    r0030b508 rfc12f05  
    1919
    2020PassVisitorStats pass_visitor_stats;
     21// TODO: There was a counter for every syntax node created.
     22//   This has not been translated to the new ast.
    2123// Stats::Counters::SimpleCounter * BaseSyntaxNode::new_nodes = nullptr;
    2224
  • src/AST/Pass.hpp

    r0030b508 rfc12f05  
    172172        const ast::Stmt *             visit( const ast::MutexStmt            * ) override final;
    173173        const ast::Stmt *             visit( const ast::CorunStmt            * ) override final;
     174        const ast::Stmt *             visit( const ast::CoforStmt            * ) override final;
    174175        const ast::Expr *             visit( const ast::ApplicationExpr      * ) override final;
    175176        const ast::Expr *             visit( const ast::UntypedExpr          * ) override final;
  • src/AST/Pass.impl.hpp

    r0030b508 rfc12f05  
    11341134
    11351135//--------------------------------------------------------------------------
     1136// CoforStmt
     1137template< typename core_t >
     1138const ast::Stmt * ast::Pass< core_t >::visit( const ast::CoforStmt * node ) {
     1139        VISIT_START( node );
     1140
     1141        if ( __visit_children() ) {
     1142                // for statements introduce a level of scope (for the initialization)
     1143                guard_symtab guard { *this };
     1144                maybe_accept( node, &CoforStmt::inits );
     1145                maybe_accept_top( node, &CoforStmt::cond  );
     1146                maybe_accept_top( node, &CoforStmt::inc   );
     1147                maybe_accept_as_compound( node, &CoforStmt::body  );
     1148        }
     1149
     1150        VISIT_END( Stmt, node );
     1151}
     1152
     1153//--------------------------------------------------------------------------
    11361154// ApplicationExpr
    11371155template< typename core_t >
  • src/AST/Print.cpp

    r0030b508 rfc12f05  
    934934        }
    935935
     936        virtual const ast::Stmt * visit( const ast::CoforStmt * node ) override final {
     937                os << "Cofor Statement" << endl;
     938
     939                if ( ! node->inits.empty() ) {
     940                        os << indent << "... initialization:" << endl;
     941                        ++indent;
     942                        for ( const ast::Stmt * stmt : node->inits ) {
     943                                os << indent+1;
     944                                safe_print( stmt );
     945                        }
     946                        --indent;
     947                }
     948
     949                if ( node->cond ) {
     950                        os << indent << "... condition:" << endl;
     951                        ++indent;
     952                        os << indent;
     953                        node->cond->accept( *this );
     954                        --indent;
     955                }
     956
     957                if ( node->inc ) {
     958                        os << indent << "... increment:" << endl;
     959                        ++indent;
     960                        os << indent;
     961                        node->inc->accept( *this );
     962                        --indent;
     963                }
     964
     965                if ( node->body ) {
     966                        os << indent << "... with body:" << endl;
     967                        ++indent;
     968                        os << indent;
     969                        node->body->accept( *this );
     970                        --indent;
     971                }
     972                os << endl;
     973                print( node->labels );
     974
     975                return node;
     976        }
     977
    936978        virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) override final {
    937979                ++indent;
  • src/AST/Stmt.hpp

    r0030b508 rfc12f05  
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    2929#define MUTATE_FRIEND                                                                                                   \
    30     template<typename node_t> friend node_t * mutate(const node_t * node); \
     30        template<typename node_t> friend node_t * mutate(const node_t * node); \
    3131        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3232
     
    340340
    341341        CatchClause( const CodeLocation & loc, ExceptionKind kind, const Decl * decl, const Expr * cond,
    342                            const Stmt * body )
     342                        const Stmt * body )
    343343                : StmtClause(loc), decl(decl), cond(cond), body(body), kind(kind) {}
    344344
     
    380380// Base class of WaitFor/WaitUntil statements
    381381// form: KEYWORD(...) ... timeout(...) ... else ...
    382 class WaitStmt : public Stmt { 
    383   public:
    384     ptr<Expr> timeout_time;
     382class WaitStmt : public Stmt {
     383  public:
     384        ptr<Expr> timeout_time;
    385385        ptr<Stmt> timeout_stmt;
    386386        ptr<Expr> timeout_cond;
     
    388388        ptr<Expr> else_cond;
    389389
    390     WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
     390        WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    391391                : Stmt(loc, std::move(labels)) {}
    392392
    393393  private:
    394     WaitStmt * clone() const override = 0;
     394        WaitStmt * clone() const override = 0;
    395395        MUTATE_FRIEND
    396396};
     
    444444class WaitUntilStmt final : public WaitStmt {
    445445  public:
    446     // Non-ast node used during compilation to store data needed to generate predicates
    447     //    and set initial status values for clauses
    448     // Used to create a tree corresponding to the structure of the clauses in a WaitUntil
    449     struct ClauseNode {
    450         enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag
    451         // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing
    452 
    453         ClauseNode * left;
    454         ClauseNode * right;
    455         WhenClause * leaf;  // only set if this node is a leaf (points into vector of clauses)
    456 
    457         bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses
    458         bool whenState;     // used to track if when_cond is toggled on or off for generating init values
    459         bool childOfAnd;      // true on leaf nodes that are children of AND, false otherwise
    460 
    461         ClauseNode( Op op, ClauseNode * left, ClauseNode * right )
    462             : op(op), left(left), right(right), leaf(nullptr),
    463             ambiguousWhen(false), whenState(true), childOfAnd(false) {}
    464         ClauseNode( Op op, WhenClause * leaf )
    465             : op(op), left(nullptr), right(nullptr), leaf(leaf),
    466             ambiguousWhen(false), whenState(true), childOfAnd(false) {}
    467         ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}
    468        
    469         ~ClauseNode() {
    470             if ( left ) delete left;
    471             if ( right ) delete right;
    472         }
    473     };
     446        // Non-ast node used during compilation to store data needed to generate predicates
     447        //    and set initial status values for clauses
     448        // Used to create a tree corresponding to the structure of the clauses in a WaitUntil
     449        struct ClauseNode {
     450                enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag
     451                // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing
     452
     453                ClauseNode * left;
     454                ClauseNode * right;
     455                WhenClause * leaf;  // only set if this node is a leaf (points into vector of clauses)
     456
     457                bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses
     458                bool whenState;     // used to track if when_cond is toggled on or off for generating init values
     459                bool childOfAnd;      // true on leaf nodes that are children of AND, false otherwise
     460
     461                ClauseNode( Op op, ClauseNode * left, ClauseNode * right )
     462                        : op(op), left(left), right(right), leaf(nullptr),
     463                        ambiguousWhen(false), whenState(true), childOfAnd(false) {}
     464                ClauseNode( Op op, WhenClause * leaf )
     465                        : op(op), left(nullptr), right(nullptr), leaf(leaf),
     466                        ambiguousWhen(false), whenState(true), childOfAnd(false) {}
     467                ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}
     468
     469                ~ClauseNode() {
     470                        if ( left ) delete left;
     471                        if ( right ) delete right;
     472                }
     473        };
    474474
    475475        std::vector<ptr<WhenClause>> clauses;
    476     ClauseNode * predicateTree;
     476        ClauseNode * predicateTree;
    477477
    478478        WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    479479                : WaitStmt(loc, std::move(labels)) {}
    480480
    481     ~WaitUntilStmt() { delete predicateTree; }
     481        ~WaitUntilStmt() { delete predicateTree; }
    482482
    483483        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    522522        std::vector<ptr<Expr>> mutexObjs;
    523523
    524         MutexStmt( const CodeLocation & loc, const Stmt * stmt, 
     524        MutexStmt( const CodeLocation & loc, const Stmt * stmt,
    525525                           const std::vector<ptr<Expr>> && mutexes, const std::vector<Label> && labels = {} )
    526526                : Stmt(loc, std::move(labels)), stmt(stmt), mutexObjs(std::move(mutexes)) {}
     
    543543  private:
    544544        CorunStmt * clone() const override { return new CorunStmt{ *this }; }
     545        MUTATE_FRIEND
     546};
     547
     548// Corun Statement
     549class CoforStmt final : public Stmt {
     550  public:
     551        std::vector<ptr<Stmt>> inits;
     552        ptr<Expr> cond;
     553        ptr<Expr> inc;
     554        ptr<Stmt> body;
     555
     556        CoforStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * cond,
     557                         const Expr * inc, const Stmt * body, const std::vector<Label> && label = {} )
     558                : Stmt(loc, std::move(label)), inits(std::move(inits)), cond(cond), inc(inc), body(body) {}
     559
     560        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     561  private:
     562        CoforStmt * clone() const override { return new CoforStmt{ *this }; }
    545563        MUTATE_FRIEND
    546564};
  • src/AST/Type.hpp

    r0030b508 rfc12f05  
    3434
    3535namespace ast {
    36 
    37 template< typename T > class Pass;
    3836
    3937class Type : public Node {
  • src/AST/Visitor.hpp

    r0030b508 rfc12f05  
    6060    virtual const ast::Stmt *             visit( const ast::MutexStmt            * ) = 0;
    6161    virtual const ast::Stmt *             visit( const ast::CorunStmt            * ) = 0;
     62    virtual const ast::Stmt *             visit( const ast::CoforStmt            * ) = 0;
    6263    virtual const ast::Expr *             visit( const ast::ApplicationExpr      * ) = 0;
    6364    virtual const ast::Expr *             visit( const ast::UntypedExpr          * ) = 0;
  • src/AST/module.mk

    r0030b508 rfc12f05  
    2020        AST/Bitfield.hpp \
    2121        AST/Chain.hpp \
    22         AST/Convert.cpp \
    23         AST/Convert.hpp \
    2422        AST/Copy.cpp \
    2523        AST/Copy.hpp \
  • src/BasicTypes-gen.cc

    r0030b508 rfc12f05  
    117117        // { LongDoubleImaginary, "LongDoubleImaginary", "LDI", "long double _Imaginary", "Ie", false, LongDoubleComplex, -1, -1, 17 },
    118118
    119         { uFloat128x, "uFloat128x", "_FBX", "_Float128x", "DF128x_", Floating, uFloat128xComplex, -1, -1, 18 }, 
     119        { uFloat128x, "uFloat128x", "_FBX", "_Float128x", "DF128x_", Floating, uFloat128xComplex, -1, -1, 18 },
    120120        { uFloat128xComplex, "uFloat128xComplex", "_FLDXC", "_Float128x _Complex", "CDF128x_", Floating, -1, -1, -1, 18 }
    121121}; // graph
     
    127127void generateCosts( int row ) {
    128128        bool seen[NUMBER_OF_BASIC_TYPES] = { false /*, ... */ };
    129        
     129
    130130        struct el_cost {
    131131                int i;
    132132                int path;
    133133                int sign;
    134                
     134
    135135                el_cost( int i = 0, int p = 0, int s = 0 ) : i(i), path(p), sign(s) {}
    136                
     136
    137137                // reverse the sense for use in largest-on-top priority queue
    138138                bool operator< (const el_cost& o) const {
     
    195195                        return;
    196196                } // if
    197                
     197
    198198                i = graph[col].middle;
    199199                if ( i == -1 ) assert("invalid ancestor assumption");
     
    272272        size_t start, end;
    273273
    274 
    275         #define TypeH TOP_SRCDIR "src/SynTree/Type.h"
    276         resetInput( file, TypeH, buffer, code, str );
    277 
    278         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH );
     274        #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp"
     275        resetInput( file, TypeH_AST, buffer, code, str );
     276
     277        if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST );
    279278        start += sizeof( STARTMK );                                                     // includes newline
    280279        code << str.substr( 0, start );
     
    284283        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    285284                code << "\t\t" << graph[r].name << "," << endl;
    286         } // for       
     285        } // for
    287286        code << "\t\tNUMBER_OF_BASIC_TYPES" << endl;
    288287        code << "\t} kind;" << endl;
    289288        code << "\t";                                                                           // indentation for end marker
    290289
    291         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH );
     290        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST );
    292291        code << str.substr( start );
    293292
    294         output( file, TypeH, code );
     293        output( file, TypeH_AST, code );
    295294        // cout << code.str();
    296295
    297296
    298         #define TypeC TOP_SRCDIR "src/SynTree/Type.cc"
    299         resetInput( file, TypeC, buffer, code, str );
    300 
    301         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC );
     297        #define TypeC_AST TOP_SRCDIR "src/AST/Type.cpp"
     298        resetInput( file, TypeC_AST, buffer, code, str );
     299
     300        if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC_AST );
    302301        start += sizeof( STARTMK );                                                     // includes newline
    303302        code << str.substr( 0, start );
     
    307306        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    308307                code << "\t\"" << graph[r].type << "\"," << endl;
    309         } // for       
    310         code << "};" << endl;
    311 
    312         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeC );
    313         code << str.substr( start );
    314 
    315         output( file, TypeC, code );
    316         // cout << code.str();
    317 
    318 
    319         // TEMPORARY DURING CHANGE OVER
    320         #define TypeH_AST TOP_SRCDIR "src/AST/Type.hpp"
    321         resetInput( file, TypeH_AST, buffer, code, str );
    322 
    323         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeH_AST );
    324         start += sizeof( STARTMK );                                                     // includes newline
    325         code << str.substr( 0, start );
    326 
    327         code << "\t" << BYMK << endl;
    328         code << "\tenum Kind {" << endl;
    329         for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    330                 code << "\t\t" << graph[r].name << "," << endl;
    331         } // for       
    332         code << "\t\tNUMBER_OF_BASIC_TYPES" << endl;
    333         code << "\t} kind;" << endl;
    334         code << "\t";                                                                           // indentation for end marker
    335 
    336         if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", TypeH_AST );
    337         code << str.substr( start );
    338 
    339         output( file, TypeH_AST, code );
    340         // cout << code.str();
    341 
    342 
    343         #define TypeC_AST TOP_SRCDIR "src/AST/Type.cpp"
    344         resetInput( file, TypeC_AST, buffer, code, str );
    345 
    346         if ( (start = str.find( STARTMK )) == string::npos ) Abort( "start", TypeC_AST );
    347         start += sizeof( STARTMK );                                                     // includes newline
    348         code << str.substr( 0, start );
    349 
    350         code << BYMK << endl;
    351         code << "const char * BasicType::typeNames[] = {" << endl;
    352         for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    353                 code << "\t\"" << graph[r].type << "\"," << endl;
    354         } // for       
     308        } // for
    355309        code << "};" << endl;
    356310
     
    391345        end += sizeof( STARTMK );
    392346        code << str.substr( start, end - start );
    393        
     347
    394348        code << "\t" << BYMK << endl;
    395         code << "\tstatic const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl
     349        code << "\tstatic const int costMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node" << endl
    396350                 << "\t\t/*           ";
    397351        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    411365        code << "\tstatic const int maxIntCost = " << *max_element(costMatrix[SignedInt], costMatrix[SignedInt] + NUMBER_OF_BASIC_TYPES) << ";" << endl;
    412366        code << "\t";                                                                           // indentation for end marker
    413        
     367
    414368        if ( (start = str.find( ENDMK, start + 1 )) == string::npos ) Abort( "end", ConversionCost );
    415369        if ( (end = str.find( STARTMK, start + 1 )) == string::npos ) Abort( "start", ConversionCost );
     
    418372
    419373        code << "\t" << BYMK << endl;
    420         code << "\tstatic const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl
     374        code << "\tstatic const int signMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion" << endl
    421375                 << "\t\t/*           ";
    422376        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    450404        enum { PER_ROW = 6 };
    451405        code << "\t" << BYMK << endl;
    452         code << "\t#define BT BasicType::" << endl;
    453         code << "\tstatic const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
     406        code << "\t#define BT ast::BasicType::" << endl;
     407        code << "\tstatic const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
    454408             << "\t\t/*\t\t ";
    455409        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
     
    505459                "\t\t\t//   - \"Di\" char32_t\n"
    506460                "\t\t\t//   - \"Ds\" char16_t\n";
    507                
    508         code << "\t\t\tconst std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;
     461
     462        code << "\t\t\tconst std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {" << endl;
    509463        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) {
    510464                code << "\t\t\t\t\"" << graph[r].mangled << "\"," << setw(9 - strlen(graph[r].mangled)) << ' ' << "// " << graph[r].type << endl;
    511         } // for       
     465        } // for
    512466        code << "\t\t\t}; // basicTypes" << endl;
    513467        code << "\t\t\t";                                                                       // indentation for end marker
  • src/CodeGen/FixMain.cc

    r0030b508 rfc12f05  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixMain.cc --
     7// FixMain.cc -- Tools to change a Cforall main into a C main.
    88//
    99// Author           : Thierry Delisle
     
    1313// Update Count     : 0
    1414//
    15 
    1615
    1716#include "FixMain.h"
     
    2322
    2423#include "AST/Decl.hpp"
     24#include "AST/Pass.hpp"
    2525#include "AST/Type.hpp"
    26 #include "Common/PassVisitor.h"
     26#include "AST/Vector.hpp"
    2727#include "Common/SemanticError.h"  // for SemanticError
    2828#include "CodeGen/GenType.h"       // for GenType
    29 #include "SynTree/Declaration.h"   // for FunctionDecl, operator<<
    30 #include "SynTree/Type.h"          // for FunctionType
    3129#include "SymTab/Mangler.h"
    3230
     
    3533namespace {
    3634
    37 struct FindMainCore {
    38         FunctionDecl * main_signature = nullptr;
     35struct FindMainCore final {
     36        ast::FunctionDecl const * main_declaration = nullptr;
    3937
    40         void previsit( FunctionDecl * decl ) {
    41                 if ( FixMain::isMain( decl ) ) {
    42                         if ( main_signature ) {
     38        void previsit( ast::FunctionDecl const * decl ) {
     39                if ( isMain( decl ) ) {
     40                        if ( main_declaration ) {
    4341                                SemanticError( decl, "Multiple definition of main routine\n" );
    4442                        }
    45                         main_signature = decl;
     43                        main_declaration = decl;
    4644                }
    4745        }
    4846};
    4947
     48std::string genTypeAt( const ast::vector<ast::Type> & types, size_t at ) {
     49        return genType( types[at], "", Options( false, false, false, false ) );
    5050}
    5151
    52         template<typename container>
    53         std::string genTypeAt(const container& p, size_t idx) {
    54                 return genType((*std::next(p.begin(), idx))->get_type(), "");
    55         }
    56 
    57         void FixMain::fix( std::list< Declaration * > & translationUnit,
    58                         std::ostream &os, const char* bootloader_filename ) {
    59                 PassVisitor< FindMainCore > main_finder;
    60                 acceptAll( translationUnit, main_finder );
    61                 FunctionDecl * main_signature = main_finder.pass.main_signature;
    62 
    63                 if( main_signature ) {
    64                         os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
    65                         main_signature->mangleName = SymTab::Mangler::mangle(main_signature);
    66 
    67                         os << main_signature->get_scopedMangleName() << "(";
    68                         const auto& params = main_signature->get_functionType()->get_parameters();
    69                         switch(params.size()) {
    70                                 case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break;
    71                                 case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break;
    72                                 case 0: break;
    73                                 default : assert(false);
    74                         }
    75                         os << "); }\n";
    76 
    77                         std::ifstream bootloader(bootloader_filename, std::ios::in);
    78                         assertf( bootloader.is_open(), "cannot open bootloader.c\n" );
    79                         os << bootloader.rdbuf();
    80                 }
    81         }
    82 
    83 namespace {
    84 
    85 ObjectDecl * signedIntObj() {
    86         return new ObjectDecl(
    87                 "", Type::StorageClasses(), LinkageSpec::Cforall, 0,
    88                 new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr );
     52ast::ObjectDecl * makeIntObj(){
     53        return new ast::ObjectDecl( CodeLocation(), "",
     54                new ast::BasicType( ast::BasicType::SignedInt ) );
    8955}
    9056
    91 ObjectDecl * makeArgvObj() {
    92         return new ObjectDecl(
    93                 "", Type::StorageClasses(), LinkageSpec::Cforall, 0,
    94                 new PointerType( Type::Qualifiers(),
    95                         new PointerType( Type::Qualifiers(),
    96                                 new BasicType( Type::Qualifiers(), BasicType::Char ) ) ),
    97                 nullptr );
     57ast::ObjectDecl * makeCharStarStarObj() {
     58        return new ast::ObjectDecl( CodeLocation(), "",
     59                new ast::PointerType(
     60                        new ast::PointerType(
     61                                new ast::BasicType( ast::BasicType::Char ) ) ) );
    9862}
    9963
    100 std::string create_mangled_main_function_name( FunctionType * function_type ) {
    101         std::unique_ptr<FunctionDecl> decl( new FunctionDecl(
    102                 "main", Type::StorageClasses(), LinkageSpec::Cforall,
    103                 function_type, nullptr ) );
    104         return SymTab::Mangler::mangle( decl.get() );
     64std::string getMangledNameOfMain(
     65                ast::vector<ast::DeclWithType> && params, ast::ArgumentFlag isVarArgs ) {
     66        ast::ptr<ast::FunctionDecl> decl = new ast::FunctionDecl(
     67                CodeLocation(),
     68                "main",
     69                ast::vector<ast::TypeDecl>(),
     70                ast::vector<ast::DeclWithType>(),
     71                std::move( params ),
     72                { makeIntObj() },
     73                nullptr,
     74                ast::Storage::Classes(),
     75                ast::Linkage::Spec(),
     76                ast::vector<ast::Attribute>(),
     77                ast::Function::Specs(),
     78                isVarArgs
     79        );
     80        return Mangle::mangle( decl.get() );
    10581}
    10682
    107 std::string mangled_0_argument_main() {
    108         FunctionType* main_type = new FunctionType( Type::Qualifiers(), true );
    109         main_type->get_returnVals().push_back( signedIntObj() );
    110         return create_mangled_main_function_name( main_type );
     83std::string getMangledNameOf0ParameterMain() {
     84        return getMangledNameOfMain( {}, ast::VariableArgs );
    11185}
    11286
    113 std::string mangled_2_argument_main() {
    114         FunctionType* main_type = new FunctionType( Type::Qualifiers(), false );
    115         main_type->get_returnVals().push_back( signedIntObj() );
    116         main_type->get_parameters().push_back( signedIntObj() );
    117         main_type->get_parameters().push_back( makeArgvObj() );
    118         return create_mangled_main_function_name( main_type );
     87std::string getMangledNameOf2ParameterMain() {
     88        return getMangledNameOfMain( {
     89                makeIntObj(),
     90                makeCharStarStarObj(),
     91        }, ast::FixedArgs );
    11992}
    12093
     
    12295        // This breaks if you move it out of the function.
    12396        static const std::string mangled_mains[] = {
    124                 mangled_0_argument_main(),
    125                 mangled_2_argument_main(),
    126                 //mangled_3_argument_main(),
     97                getMangledNameOf0ParameterMain(),
     98                getMangledNameOf2ParameterMain(),
     99                //getMangledNameOf3ParameterMain(),
    127100        };
    128101
     
    133106}
    134107
     108struct FixLinkageCore final {
     109        ast::Linkage::Spec const spec;
     110        FixLinkageCore( ast::Linkage::Spec spec ) : spec( spec ) {}
     111
     112        ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl ) {
     113                if ( decl->name != "main" ) return decl;
     114                return ast::mutate_field( decl, &ast::FunctionDecl::linkage, spec );
     115        }
     116};
     117
    135118} // namespace
    136119
    137 bool FixMain::isMain( FunctionDecl * decl ) {
    138         if ( std::string("main") != decl->name ) {
    139                 return false;
    140         }
    141         return is_main( SymTab::Mangler::mangle( decl, true, true ) );
    142 }
    143 
    144 bool FixMain::isMain( const ast::FunctionDecl * decl ) {
     120bool isMain( const ast::FunctionDecl * decl ) {
    145121        if ( std::string("main") != decl->name ) {
    146122                return false;
     
    149125}
    150126
    151 };
     127void fixMainLinkage( ast::TranslationUnit & translationUnit,
     128                bool replace_main ) {
     129        ast::Linkage::Spec const spec =
     130                ( replace_main ) ? ast::Linkage::Cforall : ast::Linkage::C;
     131        ast::Pass<FixLinkageCore>::run( translationUnit, spec );
     132}
     133
     134void fixMainInvoke( ast::TranslationUnit & translationUnit,
     135                std::ostream &os, const char * bootloader_filename ) {
     136
     137        ast::Pass<FindMainCore> main_finder;
     138        ast::accept_all( translationUnit, main_finder );
     139        if ( nullptr == main_finder.core.main_declaration ) return;
     140
     141        ast::FunctionDecl * main_declaration =
     142                ast::mutate( main_finder.core.main_declaration );
     143
     144        main_declaration->mangleName = Mangle::mangle( main_declaration );
     145
     146        os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
     147        os << main_declaration->scopedMangleName() << "(";
     148        const auto& params = main_declaration->type->params;
     149        switch ( params.size() ) {
     150                case 3: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv, (" << genTypeAt(params, 2) << ")envp"; break;
     151                case 2: os << "(" << genTypeAt(params, 0) << ")argc, (" << genTypeAt(params, 1) << ")argv"; break;
     152                case 0: break;
     153                default : assert(false);
     154        }
     155        os << "); }\n";
     156
     157        std::ifstream bootloader( bootloader_filename, std::ios::in );
     158        assertf( bootloader.is_open(), "cannot open bootloader.c\n" );
     159        os << bootloader.rdbuf();
     160}
     161
     162} // namespace CodeGen
  • src/CodeGen/FixMain.h

    r0030b508 rfc12f05  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // FixMain.h --
     7// FixMain.h -- Tools to change a Cforall main into a C main.
    88//
    99// Author           : Thierry Delisle
     
    1717
    1818#include <iosfwd>
    19 #include <memory>
    20 #include <list>
    2119
    22 #include "SynTree/LinkageSpec.h"
    23 
    24 class Declaration;
    25 class FunctionDecl;
    2620namespace ast {
    2721        class FunctionDecl;
     22        class TranslationUnit;
    2823}
    2924
    3025namespace CodeGen {
    3126
    32 class FixMain {
    33 public :
    34         static inline LinkageSpec::Spec mainLinkage() {
    35                 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;
    36         }
     27/// Is this function a program main function?
     28bool isMain( const ast::FunctionDecl * decl );
    3729
    38         static inline void setReplaceMain(bool val) {
    39                 replace_main = val;
    40         }
     30/// Adjust the linkage of main functions.
     31void fixMainLinkage( ast::TranslationUnit & transUnit, bool replaceMain );
    4132
    42         static bool isMain(FunctionDecl* decl);
    43         static bool isMain(const ast::FunctionDecl * decl);
    44 
    45         static void fix( std::list< Declaration * > & decls,
    46                         std::ostream &os, const char* bootloader_filename );
    47 
    48 private:
    49         static bool replace_main;
    50 };
     33/// Add a wrapper around to run the Cforall main.
     34void fixMainInvoke( ast::TranslationUnit & transUnit,
     35                std::ostream & os, const char * bootloaderFilename );
    5136
    5237} // namespace CodeGen
  • src/CodeGen/FixNames.cc

    r0030b508 rfc12f05  
    2222#include "AST/Expr.hpp"
    2323#include "AST/Pass.hpp"
    24 #include "Common/PassVisitor.h"
    2524#include "Common/SemanticError.h"  // for SemanticError
    2625#include "FixMain.h"               // for FixMain
    2726#include "SymTab/Mangler.h"        // for Mangler
    28 #include "SynTree/LinkageSpec.h"   // for Cforall, isMangled
    29 #include "SynTree/Constant.h"      // for Constant
    30 #include "SynTree/Declaration.h"   // for FunctionDecl, ObjectDecl, Declarat...
    31 #include "SynTree/Expression.h"    // for ConstantExpr
    32 #include "SynTree/Label.h"         // for Label, noLabels
    33 #include "SynTree/Statement.h"     // for ReturnStmt, CompoundStmt
    34 #include "SynTree/Type.h"          // for Type, BasicType, Type::Qualifiers
    35 #include "SynTree/Visitor.h"       // for Visitor, acceptAll
    3627#include "CompilationState.h"
    3728
    3829namespace CodeGen {
    39         class FixNames : public WithGuards {
    40           public:
    41                 void postvisit( ObjectDecl *objectDecl );
    42                 void postvisit( FunctionDecl *functionDecl );
    4330
    44                 void previsit( CompoundStmt *compoundStmt );
    45           private:
    46                 int scopeLevel = 1;
    47 
    48                 void fixDWT( DeclarationWithType *dwt );
    49         };
    50 
    51         void fixNames( std::list< Declaration* > & translationUnit ) {
    52                 PassVisitor<FixNames> fixer;
    53                 acceptAll( translationUnit, fixer );
    54         }
    55 
    56         void FixNames::fixDWT( DeclarationWithType * dwt ) {
    57                 if ( dwt->get_name() != "" ) {
    58                         if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) {
    59                                 if (!useNewAST) {
    60                                         dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
    61                                 }
    62                                 dwt->set_scopeLevel( scopeLevel );
    63                         } // if
    64                 } // if
    65         }
    66 
    67         void FixNames::postvisit( ObjectDecl * objectDecl ) {
    68                 fixDWT( objectDecl );
    69         }
    70 
    71         void FixNames::postvisit( FunctionDecl * functionDecl ) {
    72                 fixDWT( functionDecl );
    73 
    74                 if ( FixMain::isMain( functionDecl ) ) {
    75                         int nargs = functionDecl->get_functionType()->get_parameters().size();
    76                         if( !(nargs == 0 || nargs == 2 || nargs == 3) ) {
    77                                 SemanticError(functionDecl, "Main expected to have 0, 2 or 3 arguments\n");
    78                         }
    79                         functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( new ConstantExpr( Constant::from_int( 0 ) ) ) );
    80                 }
    81         }
    82 
    83         void FixNames::previsit( CompoundStmt * ) {
    84                 scopeLevel++;
    85                 GuardAction( [this](){ scopeLevel--; } );
    86         }
     31namespace {
    8732
    8833/// Does work with the main function and scopeLevels.
    89 class FixNames_new final {
     34class FixNames final {
    9035        int scopeLevel = 1;
    9136
     
    10348
    10449        const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) {
    105                 if ( FixMain::isMain( functionDecl ) ) {
     50                if ( isMain( functionDecl ) ) {
    10651                        auto mutDecl = ast::mutate( functionDecl );
    10752
     
    13883};
    13984
     85} // namespace
     86
    14087void fixNames( ast::TranslationUnit & translationUnit ) {
    141         ast::Pass<FixNames_new>::run( translationUnit );
     88        ast::Pass<FixNames>::run( translationUnit );
    14289}
    14390
  • src/CodeGen/FixNames.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include <list>  // for list
    19 
    20 class Declaration;
    2118namespace ast {
    2219        class TranslationUnit;
     
    2421
    2522namespace CodeGen {
    26         /// mangles object and function names
    27         void fixNames( std::list< Declaration* > & translationUnit );
     23
    2824/// Sets scope levels and fills in main's default return.
    2925void fixNames( ast::TranslationUnit & translationUnit );
     26
    3027} // namespace CodeGen
    3128
  • src/CodeGen/GenType.cc

    r0030b508 rfc12f05  
    1919#include <sstream>                // for operator<<, ostringstream, basic_os...
    2020
    21 #include "CodeGenerator.h"        // for CodeGenerator
    22 #include "SynTree/Declaration.h"  // for DeclarationWithType
    23 #include "SynTree/Expression.h"   // for Expression
    24 #include "SynTree/Type.h"         // for PointerType, Type, FunctionType
    25 #include "SynTree/Visitor.h"      // for Visitor
     21#include "AST/Print.hpp"          // for print
     22#include "AST/Vector.hpp"         // for vector
     23#include "CodeGeneratorNew.hpp"   // for CodeGenerator_new
     24#include "Common/UniqueName.h"    // for UniqueName
    2625
    2726namespace CodeGen {
    28         struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
    29                 std::string typeString;
    30                 GenType( const std::string &typeString, const Options &options );
    31 
    32                 void previsit( BaseSyntaxNode * );
    33                 void postvisit( BaseSyntaxNode * );
    34 
    35                 void postvisit( FunctionType * funcType );
    36                 void postvisit( VoidType * voidType );
    37                 void postvisit( BasicType * basicType );
    38                 void postvisit( PointerType * pointerType );
    39                 void postvisit( ArrayType * arrayType );
    40                 void postvisit( ReferenceType * refType );
    41                 void postvisit( StructInstType * structInst );
    42                 void postvisit( UnionInstType * unionInst );
    43                 void postvisit( EnumInstType * enumInst );
    44                 void postvisit( TypeInstType * typeInst );
    45                 void postvisit( TupleType  * tupleType );
    46                 void postvisit( VarArgsType * varArgsType );
    47                 void postvisit( ZeroType * zeroType );
    48                 void postvisit( OneType * oneType );
    49                 void postvisit( GlobalScopeType * globalType );
    50                 void postvisit( TraitInstType * inst );
    51                 void postvisit( TypeofType * typeof );
    52                 void postvisit( VTableType * vtable );
    53                 void postvisit( QualifiedType * qualType );
    54 
    55           private:
    56                 void handleQualifiers( Type *type );
    57                 std::string handleGeneric( ReferenceToType * refType );
    58                 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
    59 
    60                 Options options;
    61         };
    62 
    63         std::string genType( Type *type, const std::string &baseString, const Options &options ) {
    64                 PassVisitor<GenType> gt( baseString, options );
     27
     28namespace {
     29
     30#warning Remove the _new when old version is removed.
     31struct GenType_new :
     32                public ast::WithShortCircuiting,
     33                public ast::WithVisitorRef<GenType_new> {
     34        std::string result;
     35        GenType_new( const std::string &typeString, const Options &options );
     36
     37        void previsit( ast::Node const * );
     38        void postvisit( ast::Node const * );
     39
     40        void postvisit( ast::FunctionType const * type );
     41        void postvisit( ast::VoidType const * type );
     42        void postvisit( ast::BasicType const * type );
     43        void postvisit( ast::PointerType const * type );
     44        void postvisit( ast::ArrayType const * type );
     45        void postvisit( ast::ReferenceType const * type );
     46        void postvisit( ast::StructInstType const * type );
     47        void postvisit( ast::UnionInstType const * type );
     48        void postvisit( ast::EnumInstType const * type );
     49        void postvisit( ast::TypeInstType const * type );
     50        void postvisit( ast::TupleType const * type );
     51        void postvisit( ast::VarArgsType const * type );
     52        void postvisit( ast::ZeroType const * type );
     53        void postvisit( ast::OneType const * type );
     54        void postvisit( ast::GlobalScopeType const * type );
     55        void postvisit( ast::TraitInstType const * type );
     56        void postvisit( ast::TypeofType const * type );
     57        void postvisit( ast::VTableType const * type );
     58        void postvisit( ast::QualifiedType const * type );
     59
     60private:
     61        void handleQualifiers( ast::Type const *type );
     62        std::string handleGeneric( ast::BaseInstType const * type );
     63        void genArray( const ast::CV::Qualifiers &qualifiers, ast::Type const *base, ast::Expr const *dimension, bool isVarLen, bool isStatic );
     64        std::string genParamList( const ast::vector<ast::Type> & );
     65
     66        Options options;
     67};
     68
     69GenType_new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {}
     70
     71void GenType_new::previsit( ast::Node const * ) {
     72        // Turn off automatic recursion for all nodes, to allow each visitor to
     73        // precisely control the order in which its children are visited.
     74        visit_children = false;
     75}
     76
     77void GenType_new::postvisit( ast::Node const * node ) {
     78        std::stringstream ss;
     79        ast::print( ss, node );
     80        assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
     81}
     82
     83void GenType_new::postvisit( ast::VoidType const * type ) {
     84        result = "void " + result;
     85        handleQualifiers( type );
     86}
     87
     88void GenType_new::postvisit( ast::BasicType const * type ) {
     89        ast::BasicType::Kind kind = type->kind;
     90        assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES );
     91        result = std::string( ast::BasicType::typeNames[kind] ) + " " + result;
     92        handleQualifiers( type );
     93}
     94
     95void GenType_new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) {
     96        std::ostringstream os;
     97        if ( result != "" ) {
     98                if ( result[ 0 ] == '*' ) {
     99                        os << "(" << result << ")";
     100                } else {
     101                        os << result;
     102                }
     103        }
     104        os << "[";
     105        if ( isStatic ) {
     106                os << "static ";
     107        }
     108        if ( qualifiers.is_const ) {
     109                os << "const ";
     110        }
     111        if ( qualifiers.is_volatile ) {
     112                os << "volatile ";
     113        }
     114        if ( qualifiers.is_restrict ) {
     115                os << "__restrict ";
     116        }
     117        if ( qualifiers.is_atomic ) {
     118                os << "_Atomic ";
     119        }
     120        if ( dimension != 0 ) {
     121                ast::Pass<CodeGenerator_new>::read( dimension, os, options );
     122        } else if ( isVarLen ) {
     123                // no dimension expression on a VLA means it came in with the * token
     124                os << "*";
     125        }
     126        os << "]";
     127
     128        result = os.str();
     129
     130        base->accept( *visitor );
     131}
     132
     133void GenType_new::postvisit( ast::PointerType const * type ) {
     134        if ( type->isStatic || type->isVarLen || type->dimension ) {
     135                genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
     136        } else {
     137                handleQualifiers( type );
     138                if ( result[ 0 ] == '?' ) {
     139                        result = "* " + result;
     140                } else {
     141                        result = "*" + result;
     142                }
     143                type->base->accept( *visitor );
     144        }
     145}
     146
     147void GenType_new::postvisit( ast::ArrayType const * type ) {
     148        genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
     149}
     150
     151void GenType_new::postvisit( ast::ReferenceType const * type ) {
     152        assertf( !options.genC, "Reference types should not reach code generation." );
     153        handleQualifiers( type );
     154        result = "&" + result;
     155        type->base->accept( *visitor );
     156}
     157
     158void GenType_new::postvisit( ast::FunctionType const * type ) {
     159        std::ostringstream os;
     160
     161        if ( result != "" ) {
     162                if ( result[ 0 ] == '*' ) {
     163                        os << "(" << result << ")";
     164                } else {
     165                        os << result;
     166                }
     167        }
     168
     169        if ( type->params.empty() ) {
     170                if ( type->isVarArgs ) {
     171                        os << "()";
     172                } else {
     173                        os << "(void)";
     174                }
     175        } else {
     176                os << "(" ;
     177
     178                os << genParamList( type->params );
     179
     180                if ( type->isVarArgs ) {
     181                        os << ", ...";
     182                }
     183                os << ")";
     184        }
     185
     186        result = os.str();
     187
     188        if ( type->returns.size() == 0 ) {
     189                result = "void " + result;
     190        } else {
     191                type->returns.front()->accept( *visitor );
     192        }
     193
     194        // Add forall clause.
     195        if( !type->forall.empty() && !options.genC ) {
     196                //assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." );
    65197                std::ostringstream os;
    66 
    67                 if ( ! type->get_attributes().empty() ) {
    68                         PassVisitor<CodeGenerator> cg( os, options );
    69                         cg.pass.genAttributes( type->get_attributes() );
    70                 } // if
    71 
    72                 type->accept( gt );
    73                 return os.str() + gt.pass.typeString;
    74         }
    75 
    76         std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
    77                 return genType( type, baseString, Options(pretty, genC, lineMarks, false ) );
    78         }
    79 
    80         std::string genPrettyType( Type * type, const std::string & baseString ) {
    81                 return genType( type, baseString, true, false );
    82         }
    83 
    84         GenType::GenType( const std::string &typeString, const Options &options ) : typeString( typeString ), options( options ) {}
    85 
    86         // *** BaseSyntaxNode
    87         void GenType::previsit( BaseSyntaxNode * ) {
    88                 // turn off automatic recursion for all nodes, to allow each visitor to
    89                 // precisely control the order in which its children are visited.
    90                 visit_children = false;
    91         }
    92 
    93         void GenType::postvisit( BaseSyntaxNode * node ) {
    94                 std::stringstream ss;
    95                 node->print( ss );
    96                 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
    97         }
    98 
    99         void GenType::postvisit( VoidType * voidType ) {
    100                 typeString = "void " + typeString;
    101                 handleQualifiers( voidType );
    102         }
    103 
    104         void GenType::postvisit( BasicType * basicType ) {
    105                 BasicType::Kind kind = basicType->kind;
    106                 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
    107                 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
    108                 handleQualifiers( basicType );
    109         }
    110 
    111         void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) {
     198                ast::Pass<CodeGenerator_new> cg( os, options );
     199                os << "forall(";
     200                cg.core.genCommaList( type->forall );
     201                os << ")" << std::endl;
     202                result = os.str() + result;
     203        }
     204}
     205
     206std::string GenType_new::handleGeneric( ast::BaseInstType const * type ) {
     207        if ( !type->params.empty() ) {
    112208                std::ostringstream os;
    113                 if ( typeString != "" ) {
    114                         if ( typeString[ 0 ] == '*' ) {
    115                                 os << "(" << typeString << ")";
    116                         } else {
    117                                 os << typeString;
    118                         } // if
    119                 } // if
    120                 os << "[";
    121 
    122                 if ( isStatic ) {
    123                         os << "static ";
    124                 } // if
    125                 if ( qualifiers.is_const ) {
    126                         os << "const ";
    127                 } // if
    128                 if ( qualifiers.is_volatile ) {
    129                         os << "volatile ";
    130                 } // if
    131                 if ( qualifiers.is_restrict ) {
    132                         os << "__restrict ";
    133                 } // if
    134                 if ( qualifiers.is_atomic ) {
    135                         os << "_Atomic ";
    136                 } // if
    137                 if ( dimension != 0 ) {
    138                         PassVisitor<CodeGenerator> cg( os, options );
    139                         dimension->accept( cg );
    140                 } else if ( isVarLen ) {
    141                         // no dimension expression on a VLA means it came in with the * token
    142                         os << "*";
    143                 } // if
    144                 os << "]";
    145 
    146                 typeString = os.str();
    147 
    148                 base->accept( *visitor );
    149         }
    150 
    151         void GenType::postvisit( PointerType * pointerType ) {
    152                 assert( pointerType->base != 0);
    153                 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
    154                         genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
    155                 } else {
    156                         handleQualifiers( pointerType );
    157                         if ( typeString[ 0 ] == '?' ) {
    158                                 typeString = "* " + typeString;
    159                         } else {
    160                                 typeString = "*" + typeString;
    161                         } // if
    162                         pointerType->base->accept( *visitor );
    163                 } // if
    164         }
    165 
    166         void GenType::postvisit( ArrayType * arrayType ) {
    167                 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
    168         }
    169 
    170         void GenType::postvisit( ReferenceType * refType ) {
    171                 assert( 0 != refType->base );
    172                 assertf( ! options.genC, "Reference types should not reach code generation." );
    173                 handleQualifiers( refType );
    174                 typeString = "&" + typeString;
    175                 refType->base->accept( *visitor );
    176         }
    177 
    178         void GenType::postvisit( FunctionType * funcType ) {
    179                 std::ostringstream os;
    180 
    181                 if ( typeString != "" ) {
    182                         if ( typeString[ 0 ] == '*' ) {
    183                                 os << "(" << typeString << ")";
    184                         } else {
    185                                 os << typeString;
    186                         } // if
    187                 } // if
    188 
    189                 /************* parameters ***************/
    190 
    191                 const std::list<DeclarationWithType *> &pars = funcType->parameters;
    192 
    193                 if ( pars.empty() ) {
    194                         if ( funcType->get_isVarArgs() ) {
    195                                 os << "()";
    196                         } else {
    197                                 os << "(void)";
    198                         } // if
    199                 } else {
    200                         PassVisitor<CodeGenerator> cg( os, options );
    201                         os << "(" ;
    202 
    203                         cg.pass.genCommaList( pars.begin(), pars.end() );
    204 
    205                         if ( funcType->get_isVarArgs() ) {
    206                                 os << ", ...";
    207                         } // if
    208                         os << ")";
    209                 } // if
    210 
    211                 typeString = os.str();
    212 
    213                 if ( funcType->returnVals.size() == 0 ) {
    214                         typeString = "void " + typeString;
    215                 } else {
    216                         funcType->returnVals.front()->get_type()->accept( *visitor );
    217                 } // if
    218 
    219                 // add forall
    220                 if( ! funcType->forall.empty() && ! options.genC ) {
    221                         // assertf( ! genC, "Aggregate type parameters should not reach code generation." );
    222                         std::ostringstream os;
    223                         PassVisitor<CodeGenerator> cg( os, options );
    224                         os << "forall(";
    225                         cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );
    226                         os << ")" << std::endl;
    227                         typeString = os.str() + typeString;
    228                 }
    229         }
    230 
    231         std::string GenType::handleGeneric( ReferenceToType * refType ) {
    232                 if ( ! refType->parameters.empty() ) {
    233                         std::ostringstream os;
    234                         PassVisitor<CodeGenerator> cg( os, options );
    235                         os << "(";
    236                         cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
    237                         os << ") ";
    238                         return os.str();
    239                 }
    240                 return "";
    241         }
    242 
    243         void GenType::postvisit( StructInstType * structInst )  {
    244                 typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;
    245                 if ( options.genC ) typeString = "struct " + typeString;
    246                 handleQualifiers( structInst );
    247         }
    248 
    249         void GenType::postvisit( UnionInstType * unionInst ) {
    250                 typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;
    251                 if ( options.genC ) typeString = "union " + typeString;
    252                 handleQualifiers( unionInst );
    253         }
    254 
    255         void GenType::postvisit( EnumInstType * enumInst ) {
    256                 if ( enumInst->baseEnum && enumInst->baseEnum->base ) {
    257                         typeString = genType(enumInst->baseEnum->base, typeString, options);
    258                 } else {
    259                         typeString = enumInst->name + " " + typeString;
    260                         if ( options.genC ) {
    261                                 typeString = "enum " + typeString;
    262                         }
    263                 }
    264                 handleQualifiers( enumInst );
    265         }
    266 
    267         void GenType::postvisit( TypeInstType * typeInst ) {
    268                 assertf( ! options.genC, "Type instance types should not reach code generation." );
    269                 typeString = typeInst->name + " " + typeString;
    270                 handleQualifiers( typeInst );
    271         }
    272 
    273         void GenType::postvisit( TupleType * tupleType ) {
    274                 assertf( ! options.genC, "Tuple types should not reach code generation." );
    275                 unsigned int i = 0;
    276                 std::ostringstream os;
    277                 os << "[";
    278                 for ( Type * t : *tupleType ) {
    279                         i++;
    280                         os << genType( t, "", options ) << (i == tupleType->size() ? "" : ", ");
    281                 }
    282                 os << "] ";
    283                 typeString = os.str() + typeString;
    284         }
    285 
    286         void GenType::postvisit( VarArgsType * varArgsType ) {
    287                 typeString = "__builtin_va_list " + typeString;
    288                 handleQualifiers( varArgsType );
    289         }
    290 
    291         void GenType::postvisit( ZeroType * zeroType ) {
    292                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    293                 typeString = (options.pretty ? "zero_t " : "long int ") + typeString;
    294                 handleQualifiers( zeroType );
    295         }
    296 
    297         void GenType::postvisit( OneType * oneType ) {
    298                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    299                 typeString = (options.pretty ? "one_t " : "long int ") + typeString;
    300                 handleQualifiers( oneType );
    301         }
    302 
    303         void GenType::postvisit( GlobalScopeType * globalType ) {
    304                 assertf( ! options.genC, "Global scope type should not reach code generation." );
    305                 handleQualifiers( globalType );
    306         }
    307 
    308         void GenType::postvisit( TraitInstType * inst ) {
    309                 assertf( ! options.genC, "Trait types should not reach code generation." );
    310                 typeString = inst->name + " " + typeString;
    311                 handleQualifiers( inst );
    312         }
    313 
    314         void GenType::postvisit( TypeofType * typeof ) {
    315                 std::ostringstream os;
    316                 PassVisitor<CodeGenerator> cg( os, options );
    317                 os << "typeof(";
    318                 typeof->expr->accept( cg );
    319                 os << ") " << typeString;
    320                 typeString = os.str();
    321                 handleQualifiers( typeof );
    322         }
    323 
    324         void GenType::postvisit( VTableType * vtable ) {
    325                 assertf( ! options.genC, "Virtual table types should not reach code generation." );
    326                 std::ostringstream os;
    327                 os << "vtable(" << genType( vtable->base, "", options ) << ") " << typeString;
    328                 typeString = os.str();
    329                 handleQualifiers( vtable );
    330         }
    331 
    332         void GenType::postvisit( QualifiedType * qualType ) {
    333                 assertf( ! options.genC, "Qualified types should not reach code generation." );
    334                 std::ostringstream os;
    335                 os << genType( qualType->parent, "", options ) << "." << genType( qualType->child, "", options ) << typeString;
    336                 typeString = os.str();
    337                 handleQualifiers( qualType );
    338         }
    339 
    340         void GenType::handleQualifiers( Type * type ) {
    341                 if ( type->get_const() ) {
    342                         typeString = "const " + typeString;
    343                 } // if
    344                 if ( type->get_volatile() ) {
    345                         typeString = "volatile " + typeString;
    346                 } // if
    347                 if ( type->get_restrict() ) {
    348                         typeString = "__restrict " + typeString;
    349                 } // if
    350                 if ( type->get_atomic() ) {
    351                         typeString = "_Atomic " + typeString;
    352                 } // if
    353         }
     209                ast::Pass<CodeGenerator_new> cg( os, options );
     210                os << "(";
     211                cg.core.genCommaList( type->params );
     212                os << ") ";
     213                return os.str();
     214        }
     215        return "";
     216}
     217
     218void GenType_new::postvisit( ast::StructInstType const * type )  {
     219        result = type->name + handleGeneric( type ) + " " + result;
     220        if ( options.genC ) result = "struct " + result;
     221        handleQualifiers( type );
     222}
     223
     224void GenType_new::postvisit( ast::UnionInstType const * type ) {
     225        result = type->name + handleGeneric( type ) + " " + result;
     226        if ( options.genC ) result = "union " + result;
     227        handleQualifiers( type );
     228}
     229
     230void GenType_new::postvisit( ast::EnumInstType const * type ) {
     231        if ( type->base && type->base->base ) {
     232                result = genType( type->base->base, result, options );
     233        } else {
     234                result = type->name + " " + result;
     235                if ( options.genC ) {
     236                        result = "enum " + result;
     237                }
     238        }
     239        handleQualifiers( type );
     240}
     241
     242void GenType_new::postvisit( ast::TypeInstType const * type ) {
     243        assertf( !options.genC, "TypeInstType should not reach code generation." );
     244        result = type->name + " " + result;
     245        handleQualifiers( type );
     246}
     247
     248void GenType_new::postvisit( ast::TupleType const * type ) {
     249        assertf( !options.genC, "TupleType should not reach code generation." );
     250        unsigned int i = 0;
     251        std::ostringstream os;
     252        os << "[";
     253        for ( ast::ptr<ast::Type> const & t : type->types ) {
     254                i++;
     255                os << genType( t, "", options ) << (i == type->size() ? "" : ", ");
     256        }
     257        os << "] ";
     258        result = os.str() + result;
     259}
     260
     261void GenType_new::postvisit( ast::VarArgsType const * type ) {
     262        result = "__builtin_va_list " + result;
     263        handleQualifiers( type );
     264}
     265
     266void GenType_new::postvisit( ast::ZeroType const * type ) {
     267        // Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
     268        result = (options.pretty ? "zero_t " : "long int ") + result;
     269        handleQualifiers( type );
     270}
     271
     272void GenType_new::postvisit( ast::OneType const * type ) {
     273        // Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
     274        result = (options.pretty ? "one_t " : "long int ") + result;
     275        handleQualifiers( type );
     276}
     277
     278void GenType_new::postvisit( ast::GlobalScopeType const * type ) {
     279        assertf( !options.genC, "GlobalScopeType should not reach code generation." );
     280        handleQualifiers( type );
     281}
     282
     283void GenType_new::postvisit( ast::TraitInstType const * type ) {
     284        assertf( !options.genC, "TraitInstType should not reach code generation." );
     285        result = type->name + " " + result;
     286        handleQualifiers( type );
     287}
     288
     289void GenType_new::postvisit( ast::TypeofType const * type ) {
     290        std::ostringstream os;
     291        os << "typeof(";
     292        ast::Pass<CodeGenerator_new>::read( type, os, options );
     293        os << ") " << result;
     294        result = os.str();
     295        handleQualifiers( type );
     296}
     297
     298void GenType_new::postvisit( ast::VTableType const * type ) {
     299        assertf( !options.genC, "Virtual table types should not reach code generation." );
     300        std::ostringstream os;
     301        os << "vtable(" << genType( type->base, "", options ) << ") " << result;
     302        result = os.str();
     303        handleQualifiers( type );
     304}
     305
     306void GenType_new::postvisit( ast::QualifiedType const * type ) {
     307        assertf( !options.genC, "QualifiedType should not reach code generation." );
     308        std::ostringstream os;
     309        os << genType( type->parent, "", options ) << "." << genType( type->child, "", options ) << result;
     310        result = os.str();
     311        handleQualifiers( type );
     312}
     313
     314void GenType_new::handleQualifiers( ast::Type const * type ) {
     315        if ( type->is_const() ) {
     316                result = "const " + result;
     317        }
     318        if ( type->is_volatile() ) {
     319                result = "volatile " + result;
     320        }
     321        if ( type->is_restrict() ) {
     322                result = "__restrict " + result;
     323        }
     324        if ( type->is_atomic() ) {
     325                result = "_Atomic " + result;
     326        }
     327}
     328
     329std::string GenType_new::genParamList( const ast::vector<ast::Type> & range ) {
     330        auto cur = range.begin();
     331        auto end = range.end();
     332        if ( cur == end ) return "";
     333        std::ostringstream oss;
     334        UniqueName param( "__param_" );
     335        while ( true ) {
     336                oss << genType( *cur++, options.genC ? param.newName() : "", options );
     337                if ( cur == end ) break;
     338                oss << ", ";
     339        }
     340        return oss.str();
     341}
     342
     343} // namespace
     344
     345std::string genType( ast::Type const * type, const std::string & base, const Options & options ) {
     346        std::ostringstream os;
     347        if ( !type->attributes.empty() ) {
     348                ast::Pass<CodeGenerator_new> cg( os, options );
     349                cg.core.genAttributes( type->attributes );
     350        }
     351
     352        return os.str() + ast::Pass<GenType_new>::read( type, base, options );
     353}
     354
     355std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ) {
     356        return ast::Pass<GenType_new>::read( type, base, options );
     357}
     358
    354359} // namespace CodeGen
    355360
  • src/CodeGen/GenType.h

    r0030b508 rfc12f05  
    2121
    2222class Type;
     23namespace ast {
     24        class Type;
     25}
    2326
    2427namespace CodeGen {
     
    2629        std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false );
    2730        std::string genPrettyType( Type * type, const std::string & baseString );
     31
     32std::string genType( ast::Type const * type, const std::string & base, const Options & options );
     33std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options );
     34
    2835} // namespace CodeGen
    2936
  • src/CodeGen/Generate.cc

    r0030b508 rfc12f05  
    1919#include <string>                    // for operator<<
    2020
    21 #include "CodeGenerator.h"           // for CodeGenerator, doSemicolon, oper...
     21#include "CodeGeneratorNew.hpp"      // for CodeGenerator_new, doSemicolon, ...
    2222#include "GenType.h"                 // for genPrettyType
    23 #include "Common/PassVisitor.h"      // for PassVisitor
    24 #include "SynTree/LinkageSpec.h"     // for isBuiltin, isGeneratable
    25 #include "SynTree/BaseSyntaxNode.h"  // for BaseSyntaxNode
    26 #include "SynTree/Declaration.h"     // for Declaration
    27 #include "SynTree/Type.h"            // for Type
    2823
    2924using namespace std;
    3025
    3126namespace CodeGen {
    32         namespace {
    33                 /// Removes misc. nodes that should not exist in CodeGen
    34                 struct TreeCleaner {
    35                         void premutate( CompoundStmt * stmt );
    36                         Statement * postmutate( ImplicitCtorDtorStmt * stmt );
    3727
    38                         static bool shouldClean( Declaration * );
    39                 };
    40 
    41                 void cleanTree( std::list< Declaration * > & translationUnit ) {
    42                         PassVisitor<TreeCleaner> cleaner;
    43                         filter( translationUnit, [](Declaration * decl) { return TreeCleaner::shouldClean(decl); }, false );
    44                         mutateAll( translationUnit, cleaner );
    45                 } // cleanTree
    46         } // namespace
    47 
    48         void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) {
    49                 cleanTree( translationUnit );
    50 
    51                 PassVisitor<CodeGenerator> cgv( os, pretty, generateC, lineMarks, printExprTypes );
    52                 for ( auto & dcl : translationUnit ) {
    53                         if ( LinkageSpec::isGeneratable( dcl->get_linkage() ) && (doIntrinsics || ! LinkageSpec::isBuiltin( dcl->get_linkage() ) ) ) {
    54                                 cgv.pass.updateLocation( dcl );
    55                                 dcl->accept(cgv);
    56                                 if ( doSemicolon( dcl ) ) {
    57                                         os << ";";
    58                                 } // if
    59                                 os << cgv.pass.endl;
    60                         } // if
    61                 } // for
     28namespace {
     29        bool shouldClean( ast::Decl const * decl ) {
     30                return dynamic_cast<ast::TraitDecl const *>( decl );
    6231        }
    6332
    64         void generate( BaseSyntaxNode * node, std::ostream & os ) {
    65                 if ( Type * type = dynamic_cast< Type * >( node ) ) {
    66                         os << genPrettyType( type, "" );
    67                 } else {
    68                         PassVisitor<CodeGenerator> cgv( os, true, false, false, false );
    69                         node->accept( cgv );
    70                 }
    71                 os << std::endl;
    72         }
    73 
    74         namespace {
    75                 void TreeCleaner::premutate( CompoundStmt * cstmt ) {
    76                         filter( cstmt->kids, [](Statement * stmt) {
    77                                 if ( DeclStmt * declStmt = dynamic_cast< DeclStmt * >( stmt ) ) {
    78                                         return shouldClean( declStmt->decl );
    79                                 }
    80                                 return false;
    81                         }, false );
     33        /// Removes various nodes that should not exist in CodeGen.
     34        struct TreeCleaner_new {
     35                ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt ) {
     36                        auto mutStmt = ast::mutate( stmt );
     37                        erase_if( mutStmt->kids, []( ast::Stmt const * stmt ){
     38                                auto declStmt = dynamic_cast<ast::DeclStmt const *>( stmt );
     39                                return ( declStmt ) ? shouldClean( declStmt->decl ) : false;
     40                        } );
     41                        return mutStmt;
    8242                }
    8343
    84                 Statement * TreeCleaner::postmutate( ImplicitCtorDtorStmt * stmt ) {
    85                         Statement * callStmt = nullptr;
    86                         std::swap( stmt->callStmt, callStmt );
    87                         delete stmt;
    88                         return callStmt;
     44                ast::Stmt const * postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
     45                        return stmt->callStmt;
    8946                }
     47        };
     48} // namespace
    9049
    91                 bool TreeCleaner::shouldClean( Declaration * decl ) {
    92                         return dynamic_cast< TraitDecl * >( decl );
     50void generate( ast::TranslationUnit & translationUnit, std::ostream & os, bool doIntrinsics,
     51                bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) {
     52        erase_if( translationUnit.decls, shouldClean );
     53        ast::Pass<TreeCleaner_new>::run( translationUnit );
     54
     55        ast::Pass<CodeGenerator_new> cgv( os,
     56                        Options( pretty, generateC, lineMarks, printExprTypes ) );
     57        for ( auto & decl : translationUnit.decls ) {
     58                if ( decl->linkage.is_generatable && (doIntrinsics || !decl->linkage.is_builtin ) ) {
     59                        cgv.core.updateLocation( decl );
     60                        decl->accept( cgv );
     61                        if ( doSemicolon( decl ) ) {
     62                                os << ";";
     63                        }
     64                        os << cgv.core.endl;
    9365                }
    94         } // namespace
     66        }
     67}
     68
    9569} // namespace CodeGen
    9670
  • src/CodeGen/Generate.h

    r0030b508 rfc12f05  
    2222class Declaration;
    2323
     24namespace ast {
     25        class TranslationUnit;
     26}
     27
    2428namespace CodeGen {
    25         /// Generates code. doIntrinsics determines if intrinsic functions are printed, pretty formats output nicely (e.g., uses unmangled names, etc.), generateC is true when the output must consist only of C code (allows some assertions, etc.)
    26         void generate( std::list< Declaration* > translationUnit, std::ostream &os, bool doIntrinsics, bool pretty, bool generateC = false , bool lineMarks = false, bool printTypeExpr = false );
    2729
    28         /// Generate code for a single node -- helpful for debugging in gdb
    29         void generate( BaseSyntaxNode * node, std::ostream & os );
     30/// Generates all code in transUnit and writing it to the os.
     31/// doIntrinsics: Should intrinsic functions be printed?
     32/// pretty: Format output nicely (e.g., uses unmangled names, etc.).
     33/// generateC: Make sure the output only consists of C code (allows some assertions, etc.)
     34/// lineMarks: Output line marks (processed line directives) in the output.
     35/// printExprTypes: Print the types of expressions in comments.
     36void generate( ast::TranslationUnit & transUnit, std::ostream &os, bool doIntrinsics,
     37                bool pretty, bool generateC, bool lineMarks, bool printExprTypes );
     38
    3039} // namespace CodeGen
    3140
  • src/CodeGen/LinkOnce.cc

    r0030b508 rfc12f05  
    2222#include "AST/Expr.hpp"
    2323#include "AST/Pass.hpp"
    24 #include "Common/PassVisitor.h"       // for PassVisitor, WithShortCircuiting
    2524
    2625namespace CodeGen {
    2726
    2827namespace {
    29 
    30 bool is_cfa_linkonce_old( Attribute const * attr ) {
    31         return std::string("cfa_linkonce") == attr->name;
    32 }
    33 
    34 bool is_section_attribute_old( Attribute const * attr ) {
    35         return std::string("section") == attr->name;
    36 }
    37 
    38 class LinkOnceVisitorCore : public WithShortCircuiting {
    39 public:
    40         void previsit( Declaration * ) {
    41                 visit_children = false;
    42         }
    43 
    44         void previsit( DeclarationWithType * decl ) {
    45                 std::list< Attribute * > & attributes = decl->attributes;
    46                 // See if we can find the element:
    47                 auto found = std::find_if(attributes.begin(), attributes.end(), is_cfa_linkonce_old );
    48                 if ( attributes.end() != found ) {
    49                         // Remove any other sections:
    50                         attributes.remove_if( is_section_attribute_old );
    51                         // Iterator to the cfa_linkonce attribute should still be valid.
    52                         Attribute * attribute = *found;
    53                         assert( attribute->parameters.empty() );
    54                         assert( !decl->mangleName.empty() );
    55                         // Overwrite the attribute in place.
    56                         const std::string section_name = ".gnu.linkonce." + decl->mangleName;
    57                         attribute->name = "section";
    58                         attribute->parameters.push_back(
    59                                 new ConstantExpr( Constant::from_string( section_name ) )
    60                         );
    61 
    62                         // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce
    63                         // visibility is a mess otherwise
    64                         attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));
    65 
    66                 }
    67                 visit_children = false;
    68         }
    69 };
    7028
    7129bool is_cfa_linkonce( ast::Attribute const * attr ) {
     
    12280} // namespace
    12381
    124 void translateLinkOnce( std::list< Declaration *> & translationUnit ) {
    125         PassVisitor<LinkOnceVisitorCore> translator;
    126         acceptAll( translationUnit, translator );
    127 }
    128 
    12982void translateLinkOnce( ast::TranslationUnit & translationUnit ) {
    13083        ast::Pass<LinkOnceCore>::run( translationUnit );
  • src/CodeGen/LinkOnce.h

    r0030b508 rfc12f05  
    2020// for now its almost the only attribute we handle.
    2121
    22 #include <list>  // for list
    2322
    24 class Declaration;
    2523namespace ast {
    2624        class TranslationUnit;
     
    2927namespace CodeGen {
    3028
    31 void translateLinkOnce( std::list< Declaration *> & translationUnit );
    3229void translateLinkOnce( ast::TranslationUnit & translationUnit );
    3330/* Convert the cfa_linkonce attribute on top level declaration into
  • src/CodeGen/OperatorTable.cc

    r0030b508 rfc12f05  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 18 15:55:01 2020
    13 // Update Count     : 55
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Nov  3 16:00:00 2023
     13// Update Count     : 56
    1414//
    1515
    16 #include <algorithm>  // for any_of
    17 #include <map>        // for map, _Rb_tree_const_iterator, map<>::const_iterator
    18 #include <utility>    // for pair
    19 using namespace std;
     16#include "OperatorTable.h"
    2017
    21 #include "OperatorTable.h"
    22 #include "Common/utility.h"
     18#include <cassert>         // for assert
     19#include <unordered_map>   // for unordered_map
    2320
    2421namespace CodeGen {
    25         const OperatorInfo CodeGen::tableValues[] = {
    26                 // inputName symbol   outputName                     friendlyName                  type
    27                 {       "?[?]",   "",     "_operator_index",             "Index",                      OT_INDEX          },
    28                 {       "?{}",    "=",    "_constructor",                "Constructor",                OT_CTOR           },
    29                 {       "^?{}",   "",     "_destructor",                 "Destructor",                 OT_DTOR           },
    30                 {       "?()",    "",     "_operator_call",              "Call Operator",              OT_CALL           },
    31                 {       "?++",    "++",   "_operator_postincr",          "Postfix Increment",          OT_POSTFIXASSIGN  },
    32                 {       "?--",    "--",   "_operator_postdecr",          "Postfix Decrement",          OT_POSTFIXASSIGN  },
    33                 {       "*?",     "*",    "_operator_deref",             "Dereference",                OT_PREFIX         },
    34                 {       "+?",     "+",    "_operator_unaryplus",         "Plus",                       OT_PREFIX         },
    35                 {       "-?",     "-",    "_operator_unaryminus",        "Minus",                      OT_PREFIX         },
    36                 {       "~?",     "~",    "_operator_bitnot",            "Bitwise Not",                OT_PREFIX         },
    37                 {       "!?",     "!",    "_operator_lognot",            "Logical Not",                OT_PREFIX         },
    38                 {       "++?",    "++",   "_operator_preincr",           "Prefix Increment",           OT_PREFIXASSIGN   },
    39                 {       "--?",    "--",   "_operator_predecr",           "Prefix Decrement",           OT_PREFIXASSIGN   },
    40                 {       "?\\?",   "\\",   "_operator_exponential",       "Exponentiation",             OT_INFIX          },
    41                 {       "?*?",    "*",    "_operator_multiply",          "Multiplication",             OT_INFIX          },
    42                 {       "?/?",    "/",    "_operator_divide",            "Division",                   OT_INFIX          },
    43                 {       "?%?",    "%",    "_operator_modulus",           "Modulo",                     OT_INFIX          },
    44                 {       "?+?",    "+",    "_operator_add",               "Addition",                   OT_INFIX          },
    45                 {       "?-?",    "-",    "_operator_subtract",          "Substraction",               OT_INFIX          },
    46                 {       "?<<?",   "<<",   "_operator_shiftleft",         "Shift Left",                 OT_INFIX          },
    47                 {       "?>>?",   ">>",   "_operator_shiftright",        "Shift Right",                OT_INFIX          },
    48                 {       "?<?",    "<",    "_operator_less",              "Less-than",                  OT_INFIX          },
    49                 {       "?>?",    ">",    "_operator_greater",           "Greater-than",               OT_INFIX          },
    50                 {       "?<=?",   "<=",   "_operator_lessequal",         "Less-than-or-Equal",         OT_INFIX          },
    51                 {       "?>=?",   ">=",   "_operator_greaterequal",      "Greater-than-or-Equal",      OT_INFIX          },
    52                 {       "?==?",   "==",   "_operator_equal",             "Equality",                   OT_INFIX          },
    53                 {       "?!=?",   "!=",   "_operator_notequal",          "Not-Equal",                  OT_INFIX          },
    54                 {       "?&?",    "&",    "_operator_bitand",            "Bitwise And",                OT_INFIX          },
    55                 {       "?^?",    "^",    "_operator_bitxor",            "Bitwise Xor",                OT_INFIX          },
    56                 {       "?|?",    "|",    "_operator_bitor",             "Bitwise Or",                 OT_INFIX          },
    57                 {       "?=?",    "=",    "_operator_assign",            "Assignment",                 OT_INFIXASSIGN    },
    58                 {       "?\\=?",  "\\=",  "_operator_expassign",         "Exponentiation Assignment",  OT_INFIXASSIGN    },
    59                 {       "?*=?",   "*=",   "_operator_multassign",        "Multiplication Assignment",  OT_INFIXASSIGN    },
    60                 {       "?/=?",   "/=",   "_operator_divassign",         "Division Assignment",        OT_INFIXASSIGN    },
    61                 {       "?%=?",   "%=",   "_operator_modassign",         "Modulo Assignment",          OT_INFIXASSIGN    },
    62                 {       "?+=?",   "+=",   "_operator_addassign",         "Addition Assignment",        OT_INFIXASSIGN    },
    63                 {       "?-=?",   "-=",   "_operator_subassign",         "Substrction Assignment",     OT_INFIXASSIGN    },
    64                 {       "?<<=?",  "<<=",  "_operator_shiftleftassign",   "Shift Left Assignment",      OT_INFIXASSIGN    },
    65                 {       "?>>=?",  ">>=",  "_operator_shiftrightassign",  "Shift Right Assignment",     OT_INFIXASSIGN    },
    66                 {       "?&=?",   "&=",   "_operator_bitandassign",      "Bitwise And Assignment",     OT_INFIXASSIGN    },
    67                 {       "?^=?",   "^=",   "_operator_bitxorassign",      "Bitwise Xor Assignment",     OT_INFIXASSIGN    },
    68                 {       "?|=?",   "|=",   "_operator_bitorassign",       "Bitwise Or Assignment",      OT_INFIXASSIGN    },
    69         }; // tableValues
    7022
    71         std::map< std::string, OperatorInfo > CodeGen::table;
     23static const OperatorInfo tableValues[] = {
     24        //  inputName symbol  outputName                     friendlyName                  type
     25        {       "?[?]",   "",     "_operator_index",             "Index",                      OT_INDEX          },
     26        {       "?{}",    "=",    "_constructor",                "Constructor",                OT_CTOR           },
     27        {       "^?{}",   "",     "_destructor",                 "Destructor",                 OT_DTOR           },
     28        {       "?()",    "",     "_operator_call",              "Call Operator",              OT_CALL           },
     29        {       "?++",    "++",   "_operator_postincr",          "Postfix Increment",          OT_POSTFIXASSIGN  },
     30        {       "?--",    "--",   "_operator_postdecr",          "Postfix Decrement",          OT_POSTFIXASSIGN  },
     31        {       "*?",     "*",    "_operator_deref",             "Dereference",                OT_PREFIX         },
     32        {       "+?",     "+",    "_operator_unaryplus",         "Plus",                       OT_PREFIX         },
     33        {       "-?",     "-",    "_operator_unaryminus",        "Minus",                      OT_PREFIX         },
     34        {       "~?",     "~",    "_operator_bitnot",            "Bitwise Not",                OT_PREFIX         },
     35        {       "!?",     "!",    "_operator_lognot",            "Logical Not",                OT_PREFIX         },
     36        {       "++?",    "++",   "_operator_preincr",           "Prefix Increment",           OT_PREFIXASSIGN   },
     37        {       "--?",    "--",   "_operator_predecr",           "Prefix Decrement",           OT_PREFIXASSIGN   },
     38        {       "?\\?",   "\\",   "_operator_exponential",       "Exponentiation",             OT_INFIX          },
     39        {       "?*?",    "*",    "_operator_multiply",          "Multiplication",             OT_INFIX          },
     40        {       "?/?",    "/",    "_operator_divide",            "Division",                   OT_INFIX          },
     41        {       "?%?",    "%",    "_operator_modulus",           "Modulo",                     OT_INFIX          },
     42        {       "?+?",    "+",    "_operator_add",               "Addition",                   OT_INFIX          },
     43        {       "?-?",    "-",    "_operator_subtract",          "Substraction",               OT_INFIX          },
     44        {       "?<<?",   "<<",   "_operator_shiftleft",         "Shift Left",                 OT_INFIX          },
     45        {       "?>>?",   ">>",   "_operator_shiftright",        "Shift Right",                OT_INFIX          },
     46        {       "?<?",    "<",    "_operator_less",              "Less-than",                  OT_INFIX          },
     47        {       "?>?",    ">",    "_operator_greater",           "Greater-than",               OT_INFIX          },
     48        {       "?<=?",   "<=",   "_operator_lessequal",         "Less-than-or-Equal",         OT_INFIX          },
     49        {       "?>=?",   ">=",   "_operator_greaterequal",      "Greater-than-or-Equal",      OT_INFIX          },
     50        {       "?==?",   "==",   "_operator_equal",             "Equality",                   OT_INFIX          },
     51        {       "?!=?",   "!=",   "_operator_notequal",          "Not-Equal",                  OT_INFIX          },
     52        {       "?&?",    "&",    "_operator_bitand",            "Bitwise And",                OT_INFIX          },
     53        {       "?^?",    "^",    "_operator_bitxor",            "Bitwise Xor",                OT_INFIX          },
     54        {       "?|?",    "|",    "_operator_bitor",             "Bitwise Or",                 OT_INFIX          },
     55        {       "?=?",    "=",    "_operator_assign",            "Assignment",                 OT_INFIXASSIGN    },
     56        {       "?\\=?",  "\\=",  "_operator_expassign",         "Exponentiation Assignment",  OT_INFIXASSIGN    },
     57        {       "?*=?",   "*=",   "_operator_multassign",        "Multiplication Assignment",  OT_INFIXASSIGN    },
     58        {       "?/=?",   "/=",   "_operator_divassign",         "Division Assignment",        OT_INFIXASSIGN    },
     59        {       "?%=?",   "%=",   "_operator_modassign",         "Modulo Assignment",          OT_INFIXASSIGN    },
     60        {       "?+=?",   "+=",   "_operator_addassign",         "Addition Assignment",        OT_INFIXASSIGN    },
     61        {       "?-=?",   "-=",   "_operator_subassign",         "Substrction Assignment",     OT_INFIXASSIGN    },
     62        {       "?<<=?",  "<<=",  "_operator_shiftleftassign",   "Shift Left Assignment",      OT_INFIXASSIGN    },
     63        {       "?>>=?",  ">>=",  "_operator_shiftrightassign",  "Shift Right Assignment",     OT_INFIXASSIGN    },
     64        {       "?&=?",   "&=",   "_operator_bitandassign",      "Bitwise And Assignment",     OT_INFIXASSIGN    },
     65        {       "?^=?",   "^=",   "_operator_bitxorassign",      "Bitwise Xor Assignment",     OT_INFIXASSIGN    },
     66        {       "?|=?",   "|=",   "_operator_bitorassign",       "Bitwise Or Assignment",      OT_INFIXASSIGN    },
     67}; // tableValues
    7268
    73         CodeGen::CodeGen() {
    74                 enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) };
    75                 for ( int i = 0; i < numOps; i += 1 ) {
    76                         table[ tableValues[i].inputName ] = tableValues[i];
    77                 } // for
     69enum { numOps = sizeof( tableValues ) / sizeof( OperatorInfo ) };
     70
     71const OperatorInfo * operatorLookup( const std::string & inputName ) {
     72        // Static information set up:
     73        static std::unordered_map<std::string, const OperatorInfo *> inputTable;
     74        if ( inputTable.empty() ) for ( const OperatorInfo & op : tableValues ) {
     75                inputTable[ op.inputName ] = &op;
    7876        }
    7977
    80         const OperatorInfo * operatorLookup( const string & funcName ) {
    81                 if ( funcName.find_first_of( "?^*+-!", 0, 1 ) == string::npos ) return nullptr; // prefilter
    82                 const OperatorInfo * ret = &CodeGen::table.find( funcName )->second; // must be in the table
    83                 assert( ret );
    84                 return ret;
     78        if ( inputName.find_first_of( "?^*+-!", 0, 1 ) == std::string::npos ) return nullptr; // prefilter
     79        const OperatorInfo * ret = inputTable.find( inputName )->second;
     80        // This can only happen if an invalid identifier name has been used.
     81        assert( ret );
     82        return ret;
     83}
     84
     85bool isOperator( const std::string & inputName ) {
     86        return operatorLookup( inputName ) != nullptr;
     87}
     88
     89std::string operatorFriendlyName( const std::string & inputName ) {
     90        const OperatorInfo * info = operatorLookup( inputName );
     91        if ( info ) return info->friendlyName;
     92        return "";
     93}
     94
     95// This is only used in the demangler, so it is smaller (and only maybe slow).
     96const OperatorInfo * operatorLookupByOutput( const std::string & outputName ) {
     97        if ( '_' != outputName[0] ) return nullptr;
     98        for ( const OperatorInfo & op : tableValues ) {
     99                if ( outputName == op.outputName ) {
     100                        return &op;
     101                }
    85102        }
     103        return nullptr;
     104}
    86105
    87         bool isOperator( const string & funcName ) {
    88                 return operatorLookup( funcName ) != nullptr;
    89         }
     106bool isConstructor( const std::string & inputName ) {
     107        const OperatorInfo * info = operatorLookup( inputName );
     108        if ( info ) return info->type == OT_CTOR;
     109        return false;
     110}
    90111
    91         string operatorFriendlyName( const string & funcName ) {
    92                 const OperatorInfo * info = operatorLookup( funcName );
    93                 if ( info ) return info->friendlyName;
    94                 return "";
    95         }
     112bool isDestructor( const std::string & inputName ) {
     113        const OperatorInfo * info = operatorLookup( inputName );
     114        if ( info ) return info->type == OT_DTOR;
     115        return false;
     116}
    96117
    97         bool isConstructor( const string & funcName ) {
    98                 const OperatorInfo * info = operatorLookup( funcName );
    99                 if ( info ) return info->type == OT_CTOR;
    100                 return false;
    101         }
     118bool isCtorDtor( const std::string & inputName ) {
     119        const OperatorInfo * info = operatorLookup( inputName );
     120        if ( info ) return info->type <= OT_CONSTRUCTOR;
     121        return false;
     122}
    102123
    103         bool isDestructor( const string & funcName ) {
    104                 const OperatorInfo * info = operatorLookup( funcName );
    105                 if ( info ) return info->type == OT_DTOR;
    106                 return false;
    107         }
     124bool isAssignment( const std::string & inputName ) {
     125        const OperatorInfo * info = operatorLookup( inputName );
     126        if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT;
     127        return false;
     128}
    108129
    109         bool isCtorDtor( const string & funcName ) {
    110                 const OperatorInfo * info = operatorLookup( funcName );
    111                 if ( info ) return info->type <= OT_CONSTRUCTOR;
    112                 return false;
    113         }
     130bool isCtorDtorAssign( const std::string & inputName ) {
     131        const OperatorInfo * info = operatorLookup( inputName );
     132        if ( info ) return info->type <= OT_ASSIGNMENT;
     133        return false;
     134}
    114135
    115         bool isAssignment( const string & funcName ) {
    116                 const OperatorInfo * info = operatorLookup( funcName );
    117                 if ( info ) return info->type > OT_CONSTRUCTOR && info->type <= OT_ASSIGNMENT;
    118                 return false;
    119         }
    120 
    121         bool isCtorDtorAssign( const string & funcName ) {
    122                 const OperatorInfo * info = operatorLookup( funcName );
    123                 if ( info ) return info->type <= OT_ASSIGNMENT;
    124                 return false;
    125         }
    126 
    127         CodeGen codegen;                                                                        // initialize singleton package
    128136} // namespace CodeGen
    129137
  • src/CodeGen/OperatorTable.h

    r0030b508 rfc12f05  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 08:13:34 2020
    13 // Update Count     : 26
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Nov  3 14:53:00 2023
     13// Update Count     : 27
    1414//
    1515
     
    1717
    1818#include <string>
    19 #include <map>
    2019
    2120namespace CodeGen {
    22         enum OperatorType {
    23                 OT_CTOR,
    24                 OT_DTOR,
    25                 OT_CONSTRUCTOR = OT_DTOR,
    26                 OT_PREFIXASSIGN,
    27                 OT_POSTFIXASSIGN,
    28                 OT_INFIXASSIGN,
    29                 OT_ASSIGNMENT = OT_INFIXASSIGN,
    30                 OT_CALL,
    31                 OT_PREFIX,
    32                 OT_INFIX,
    33                 OT_POSTFIX,
    34                 OT_INDEX,
    35                 OT_LABELADDRESS,
    36                 OT_CONSTANT
    37         };
    3821
    39         struct OperatorInfo {
    40                 std::string inputName;
    41                 std::string symbol;
    42                 std::string outputName;
    43                 std::string friendlyName;
    44                 OperatorType type;
    45         };
     22enum OperatorType {
     23        OT_CTOR,
     24        OT_DTOR,
     25        OT_CONSTRUCTOR = OT_DTOR,
     26        OT_PREFIXASSIGN,
     27        OT_POSTFIXASSIGN,
     28        OT_INFIXASSIGN,
     29        OT_ASSIGNMENT = OT_INFIXASSIGN,
     30        OT_CALL,
     31        OT_PREFIX,
     32        OT_INFIX,
     33        OT_POSTFIX,
     34        OT_INDEX,
     35        OT_LABELADDRESS,
     36        OT_CONSTANT
     37};
    4638
    47         class CodeGen {
    48                 friend const OperatorInfo * operatorLookup( const std::string & funcName );
     39struct OperatorInfo {
     40        // The Cforall special function name.
     41        std::string inputName;
     42        // The string used when the operator is used as an operator.
     43        std::string symbol;
     44        // The base name used in the mangled name.
     45        std::string outputName;
     46        // Human-readable name of the operator.
     47        std::string friendlyName;
     48        // The type of operator shows how it is used as an operator.
     49        OperatorType type;
     50};
    4951
    50                 static const OperatorInfo tableValues[];
    51                 static std::map< std::string, OperatorInfo > table;
    52           public:
    53                 CodeGen();
    54         }; // CodeGen
     52// Look up the operator (by inputName), return nullptr if no such operator.
     53const OperatorInfo * operatorLookup( const std::string & inputName );
     54// Is there an operator with this name?
     55bool isOperator( const std::string & inputName );
     56// Get the friendlyName of the operator with the inputName
     57std::string operatorFriendlyName( const std::string & inputName );
     58// Get the OperatorInfo with the given outputName, if one exists.
     59const OperatorInfo * operatorLookupByOutput( const std::string & outputName );
    5560
    56         bool isOperator( const std::string & funcName );
    57         const OperatorInfo * operatorLookup( const std::string & funcName );
    58         std::string operatorFriendlyName( const std::string & funcName );
     61// Is the operator a constructor, destructor or any form of assignment.
     62// (Last two are "or" combinations of the first three.)
     63bool isConstructor( const std::string & );
     64bool isDestructor( const std::string & );
     65bool isAssignment( const std::string & );
     66bool isCtorDtor( const std::string & );
     67bool isCtorDtorAssign( const std::string & );
    5968
    60         bool isConstructor( const std::string & );
    61         bool isDestructor( const std::string & );
    62         bool isAssignment( const std::string & );
    63         bool isCtorDtor( const std::string & );
    64         bool isCtorDtorAssign( const std::string & );
    6569} // namespace CodeGen
    6670
  • src/CodeGen/module.mk

    r0030b508 rfc12f05  
    1616
    1717SRC_CODEGEN = \
    18         CodeGen/FixMain2.cc \
    19         CodeGen/FixMain.h \
     18        CodeGen/CodeGeneratorNew.cpp \
     19        CodeGen/CodeGeneratorNew.hpp \
     20        CodeGen/GenType.cc \
     21        CodeGen/GenType.h \
    2022        CodeGen/OperatorTable.cc \
    2123        CodeGen/OperatorTable.h
    2224
    2325SRC += $(SRC_CODEGEN) \
    24         CodeGen/CodeGenerator.cc \
    25         CodeGen/CodeGenerator.h \
    2626        CodeGen/Generate.cc \
    2727        CodeGen/Generate.h \
    2828        CodeGen/FixMain.cc \
     29        CodeGen/FixMain.h \
    2930        CodeGen/FixNames.cc \
    3031        CodeGen/FixNames.h \
    31         CodeGen/GenType.cc \
    32         CodeGen/GenType.h \
    3332        CodeGen/LinkOnce.cc \
    3433        CodeGen/LinkOnce.h \
  • src/Common/CodeLocationTools.cpp

    r0030b508 rfc12f05  
    138138    macro(MutexStmt, Stmt) \
    139139    macro(CorunStmt, Stmt) \
     140        macro(CoforStmt, Stmt) \
    140141    macro(ApplicationExpr, Expr) \
    141142    macro(UntypedExpr, Expr) \
  • src/Common/Eval.cc

    r0030b508 rfc12f05  
    1919
    2020#include "AST/Inspect.hpp"
    21 #include "Common/PassVisitor.h"
    2221#include "CodeGen/OperatorTable.h"                                              // access: OperatorInfo
    2322#include "AST/Pass.hpp"
    2423#include "InitTweak/InitTweak.h"
    25 #include "SynTree/Expression.h"
    26 
    27 //-------------------------------------------------------------
    28 // Old AST
    29 struct EvalOld : public WithShortCircuiting {
    30         long long int value = 0;                                                        // compose the result of the constant expression
    31         bool valid = true;                                                                      // true => constant expression and value is the result
    32                                                                                                                 // false => not constant expression, e.g., ++i
    33         bool cfavalid = true;                                                           // true => constant expression and value computable
    34                                                                                                                 // false => constant expression but value not computable, e.g., sizeof(int)
    35 
    36         void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    37         void postvisit( const BaseSyntaxNode * ) { valid = false; }
    38 
    39         void postvisit( const SizeofExpr * ) {
    40         }
    41 
    42         void postvisit( const ConstantExpr * expr ) {
    43                 value = expr->intValue();
    44         }
    45 
    46         void postvisit( const CastExpr * expr ) {
    47                 auto arg = eval(expr->arg);
    48                 valid = arg.second;
    49                 value = arg.first;
    50                 // TODO: perform type conversion on value if valid
    51         }
    52 
    53         void postvisit( const VariableExpr * const expr ) {
    54                 if ( EnumInstType * inst = dynamic_cast<EnumInstType *>(expr->result) ) {
    55                         if ( EnumDecl * decl = inst->baseEnum ) {
    56                                 if ( decl->valueOf( expr->var, value ) ) { // value filled by valueOf
    57                                         return;
    58                                 }
    59                         }
    60                 }
    61                 valid = false;
    62         }
    63 
    64         void postvisit( const ApplicationExpr * expr ) {
    65                 DeclarationWithType * function = InitTweak::getFunction(const_cast<ApplicationExpr *>(expr));
    66                 if ( ! function || function->linkage != LinkageSpec::Intrinsic ) { valid = false; return; }
    67                 const std::string & fname = function->name;
    68                 assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
    69                 std::pair<long long int, bool> arg1, arg2;
    70                 arg1 = eval(expr->args.front());
    71                 valid = valid && arg1.second;
    72                 if ( ! valid ) return;
    73                 if ( expr->args.size() == 2 ) {
    74                         arg2 = eval(expr->args.back());
    75                         valid = valid && arg2.second;
    76                         if ( ! valid ) return;
    77                 }
    78                 if (fname == "?+?") {
    79                         value = arg1.first + arg2.first;
    80                 } else if (fname == "?-?") {
    81                         value = arg1.first - arg2.first;
    82                 } else if (fname == "?*?") {
    83                         value = arg1.first * arg2.first;
    84                 } else if (fname == "?/?") {
    85                         value = arg1.first / arg2.first;
    86                 } else if (fname == "?%?") {
    87                         value = arg1.first % arg2.first;
    88                 } else {
    89                         valid = false;
    90                 }
    91                 // TODO: implement other intrinsic functions
    92         }
    93 };
    94 
    95 //-------------------------------------------------------------
    96 // New AST
     24
    9725struct EvalNew : public ast::WithShortCircuiting {
    9826        Evaluation result = { 0, true, true };
     
    270198};
    271199
    272 std::pair<long long int, bool> eval( const Expression * expr ) {
    273         PassVisitor<EvalOld> ev;
    274         if ( expr ) {
    275                 expr->accept( ev );
    276                 return std::make_pair( ev.pass.value, ev.pass.valid );
    277         } else {
    278                 return std::make_pair( 0, false );
    279         }
    280 }
    281 
    282200Evaluation eval( const ast::Expr * expr ) {
    283201        if ( expr ) {
  • src/Common/Eval.h

    r0030b508 rfc12f05  
    3030
    3131/// Evaluates expr as a long long int.
    32 /// If second is false, expr could not be evaluated.
    33 std::pair<long long int, bool> eval(const Expression * expr);
    3432Evaluation eval(const ast::Expr * expr);
    3533
  • src/Common/Examine.cc

    r0030b508 rfc12f05  
    1919#include "CodeGen/OperatorTable.h"
    2020#include "InitTweak/InitTweak.h"
    21 
    22 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) {
    23         if (func->name != "main") return nullptr;
    24         if (func->type->parameters.size() != 1) return nullptr;
    25 
    26         auto param = func->type->parameters.front();
    27 
    28         auto type = dynamic_cast<ReferenceType * >(param->get_type());
    29         if (!type) return nullptr;
    30 
    31         auto obj = dynamic_cast<StructInstType *>(type->base);
    32         if (!obj) return nullptr;
    33 
    34         if (kind != obj->baseStruct->kind) return nullptr;
    35 
    36         return param;
    37 }
    3821
    3922namespace {
     
    6952
    7053namespace {
    71         Type * getDestructorParam( FunctionDecl * func ) {
    72                 if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
    73 
    74                 auto params = func->type->parameters;
    75                 if ( 1 != params.size() ) return nullptr;
    76 
    77                 auto ref = dynamic_cast<ReferenceType *>( params.front()->get_type() );
    78                 if ( ref ) {
    79                         return ref->base;
    80                 }
    81                 return nullptr;
    82         }
    8354
    8455const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) {
     
    8859}
    8960
    90 }
    91 
    92 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl ) {
    93         if ( Type * type = getDestructorParam( func ) ) {
    94                 auto stype = dynamic_cast<StructInstType *>( type );
    95                 return stype && stype->baseStruct == type_decl;
    96         }
    97         return false;
    9861}
    9962
  • src/Common/Examine.h

    r0030b508 rfc12f05  
    1515
    1616#include "AST/Decl.hpp"
    17 #include "SynTree/Declaration.h"
    1817
    1918/// Check if this is a main function for a type of an aggregate kind.
    20 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );
    2119const ast::DeclWithType * isMainFor(
    2220        const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind );
     
    2422
    2523/// Check if this function is a destructor for the given structure.
    26 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );
    2724bool isDestructorFor(
    2825        const ast::FunctionDecl * func, const ast::StructDecl * type );
  • src/Common/UniqueName.cc

    r0030b508 rfc12f05  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // UniqueName.cc --
     7// UniqueName.cc -- Create a unique variants of a base name with a counter.
    88//
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jun  8 14:47:49 2015
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Nov  7 15:04:00 2023
     13// Update Count     : 4
    1414//
    1515
    16 #include <string>
    17 #include <sstream>
     16#include "UniqueName.h"
    1817
    19 #include "UniqueName.h"
     18#include "Common/ToString.hpp"
    2019
    2120UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) {
     
    2322
    2423std::string UniqueName::newName( const std::string &additional ) {
    25         std::ostringstream os;
    26         os << base << additional << count++;
    27         return os.str();
     24        return toString( base, additional, count++ );
    2825}
    2926
  • src/Common/UniqueName.h

    r0030b508 rfc12f05  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // UniqueName.h --
     7// UniqueName.h -- Create a unique variants of a base name with a counter.
    88//
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 21 22:18:45 2017
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Nov  7 15:00:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    1919
    2020class UniqueName {
    21   public:
    22         UniqueName( const std::string &base = "" );
     21public:
     22        UniqueName( const std::string &base );
    2323        std::string newName( const std::string &additional = "" );
    24   private:
     24private:
    2525        std::string base;
    2626        int count;
  • src/Common/module.mk

    r0030b508 rfc12f05  
    3131        Common/Indenter.cc \
    3232        Common/Iterate.hpp \
    33         Common/PassVisitor.cc \
    34         Common/PassVisitor.h \
    35         Common/PassVisitor.impl.h \
    36         Common/PassVisitor.proto.h \
    3733        Common/PersistentMap.h \
    3834        Common/ResolvProtoDump.hpp \
  • src/Concurrency/Corun.cpp

    r0030b508 rfc12f05  
    2727struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> {
    2828    UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
     29    UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
     30    // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
    2931    UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
     32   
     33    string coforArgName = "__CFA_cofor_lambda_arg";
     34    string numProcsName = "__CFA_cofor_num_procs";
     35    string currProcsName = "__CFA_cofor_curr_procs";
     36    string thdArrName = "__CFA_cofor_thread_array";
     37    string loopTempName = "__CFA_cofor_loop_temp";
     38   
    3039
    3140    const StructDecl * runnerBlockDecl = nullptr;
    32 
    33     // Finds select_node decl
     41    const StructDecl * coforRunnerDecl = nullptr;
     42
     43    // Finds runner_block (corun task) and cofor_runner (cofor task) decls
    3444    void previsit( const StructDecl * decl ) {
    3545        if ( !decl->body ) {
     
    3848            assert( !runnerBlockDecl );
    3949            runnerBlockDecl = decl;
     50        } else if ( "cofor_runner" == decl->name ) {
     51            assert( !coforRunnerDecl );
     52            coforRunnerDecl = decl;
    4053        }
    4154    }
    4255
     56    // codegen for cofor statements
     57    Stmt * postvisit( const CoforStmt * stmt ) {
     58        if ( !runnerBlockDecl || !coforRunnerDecl )
     59            SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>\n" );
     60
     61        if ( stmt->inits.size() != 1 )
     62            SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control\n" );
     63
     64        if ( !stmt->body )
     65            return nullptr;
     66
     67        const CodeLocation & loc = stmt->location;
     68        const string fnName = CoforFnNamer.newName();
     69
     70        CompoundStmt * body = new CompoundStmt( loc );
     71
     72        // push back cofor initializer to generated body
     73        body->push_back( deepCopy( stmt->inits.at(0) ) );
     74
     75        CompoundStmt * fnBody = new CompoundStmt( loc );
     76
     77        const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
     78        if ( ! declStmtPtr )
     79            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?\n" );
     80
     81        const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
     82        if ( ! declPtr )
     83            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?\n" );
     84
     85        Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
     86
     87        // Generates:
     88        // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
     89        fnBody->push_back( new DeclStmt( loc,
     90            new ObjectDecl( loc,
     91                declPtr->name,
     92                initType,
     93                new SingleInit( loc,
     94                    UntypedExpr::createDeref( loc,
     95                        new CastExpr( loc,
     96                            new NameExpr( loc, coforArgName ),
     97                            new PointerType( initType ), ExplicitCast
     98                        )
     99                    )
     100                )
     101            )
     102        ));
     103
     104        // push rest of cofor body into loop lambda
     105        fnBody->push_back( deepCopy( stmt->body ) );
     106
     107        // Generates:
     108        // void __CFA_cofor_lambda_() {
     109        //    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
     110        //    stmt->body;
     111        // }
     112        Stmt * coforLambda = new DeclStmt( loc,
     113            new FunctionDecl( loc,
     114                fnName,                                             // name
     115                {},                                                 // forall
     116                {
     117                    new ObjectDecl( loc,
     118                        coforArgName,
     119                        new ast::PointerType( new ast::VoidType() )
     120                    )
     121                },                                                  // params
     122                {},                                                 // return
     123                fnBody   // body
     124            )
     125        );
     126        body->push_back( coforLambda );
     127
     128        // Generates:
     129        // unsigned __CFA_cofor_num_procs = get_proc_count();
     130        body->push_back( new DeclStmt( loc,
     131                new ObjectDecl( loc,
     132                    numProcsName,
     133                    new BasicType( BasicType::Kind::UnsignedInt ),
     134                    new SingleInit( loc,
     135                        new UntypedExpr( loc,
     136                            new NameExpr( loc, "get_proc_count" ),
     137                            {}
     138                        )
     139                    )
     140                )
     141            )
     142        );
     143
     144        // Generates:
     145        // unsigned __CFA_cofor_curr_procs = 0;
     146        body->push_back( new DeclStmt( loc,
     147                new ObjectDecl( loc,
     148                    currProcsName,
     149                    new BasicType( BasicType::Kind::UnsignedInt ),
     150                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     151                )
     152            )
     153        );
     154
     155        // Generates:
     156        // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
     157        body->push_back( new DeclStmt( loc,
     158                new ObjectDecl( loc,
     159                    thdArrName,
     160                    new ast::ArrayType(
     161                        new StructInstType( coforRunnerDecl ),
     162                        new NameExpr( loc, numProcsName ),
     163                        ast::FixedLen,
     164                        ast::DynamicDim
     165                    )
     166                )
     167            )
     168        );
     169
     170        // Generates:
     171        // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
     172        body->push_back( new ExprStmt( loc,
     173            new UntypedExpr( loc,
     174                new NameExpr( loc, "start_runners" ),
     175                {
     176                    new NameExpr( loc, thdArrName ),
     177                    new NameExpr( loc, numProcsName ),
     178                    new NameExpr( loc, fnName )
     179                }
     180            )
     181        ));
     182
     183        // Generates:
     184        // typeof(initializer) * __CFA_cofor_loop_temp = malloc();
     185        CompoundStmt * forLoopBody = new CompoundStmt( loc );
     186        forLoopBody->push_back( new DeclStmt( loc,
     187                new ObjectDecl( loc,
     188                    loopTempName,
     189                    new PointerType( initType ),
     190                    new SingleInit( loc,
     191                        new UntypedExpr( loc,
     192                            new NameExpr( loc, "malloc" ),
     193                            {}
     194                        )
     195                    )
     196                )
     197            )
     198        );
     199
     200        // Generates:
     201        // *__CFA_cofor_loop_temp = initializer;
     202        forLoopBody->push_back( new ExprStmt( loc,
     203            UntypedExpr::createAssign( loc,
     204                UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
     205                new NameExpr( loc, declPtr->name )
     206            )
     207        ));
     208
     209        // Generates:
     210        // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
     211        //     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
     212        forLoopBody->push_back( new ExprStmt( loc,
     213            new UntypedExpr( loc,
     214                new NameExpr( loc, "send_work" ),
     215                {
     216                    new NameExpr( loc, thdArrName ),
     217                    new NameExpr( loc, numProcsName ),
     218                    new NameExpr( loc, currProcsName ),
     219                    new NameExpr( loc, loopTempName )
     220                }
     221            )
     222        ));
     223
     224        body->push_back( new ForStmt( loc,
     225            {},
     226            deepCopy( stmt->cond ),
     227            deepCopy( stmt->inc ),
     228            forLoopBody
     229        ));
     230
     231        // Generates:
     232        // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
     233        body->push_back( new ExprStmt( loc,
     234            new UntypedExpr( loc,
     235                new NameExpr( loc, "end_runners" ),
     236                {
     237                    new NameExpr( loc, thdArrName ),
     238                    new NameExpr( loc, numProcsName )
     239                }
     240            )
     241        ));
     242
     243        return body;
     244    }
     245
     246    // codegen for corun statements
    43247    Stmt * postvisit( const CorunStmt * stmt ) {
    44         if ( !runnerBlockDecl )
     248        if ( !runnerBlockDecl || !coforRunnerDecl )
    45249            SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>\n" );
    46250
  • src/Concurrency/module.mk

    r0030b508 rfc12f05  
    2121        Concurrency/Corun.hpp \
    2222        Concurrency/KeywordsNew.cpp \
    23         Concurrency/Keywords.cc \
    2423        Concurrency/Keywords.h \
    2524        Concurrency/WaitforNew.cpp \
    26         Concurrency/Waitfor.cc \
    2725        Concurrency/Waitfor.h \
    2826        Concurrency/Waituntil.cpp \
  • src/ControlStruct/module.mk

    r0030b508 rfc12f05  
    1616
    1717SRC += \
    18         ControlStruct/ExceptDecl.cc \
    1918        ControlStruct/ExceptDeclNew.cpp \
    2019        ControlStruct/ExceptDecl.h \
    2120        ControlStruct/ExceptTranslateNew.cpp \
    22         ControlStruct/ExceptTranslate.cc \
    2321        ControlStruct/ExceptTranslate.h \
    2422        ControlStruct/FixLabels.cpp \
    2523        ControlStruct/FixLabels.hpp \
    26         ControlStruct/ForExprMutator.cc \
    27         ControlStruct/ForExprMutator.h \
    2824        ControlStruct/HoistControlDecls.cpp \
    2925        ControlStruct/HoistControlDecls.hpp \
    30         ControlStruct/LabelFixer.cc \
    31         ControlStruct/LabelFixer.h \
    32         ControlStruct/LabelGenerator.cc \
    33         ControlStruct/LabelGenerator.h \
    3426        ControlStruct/LabelGeneratorNew.cpp \
    3527        ControlStruct/LabelGeneratorNew.hpp \
    36         ControlStruct/MLEMutator.cc \
    37         ControlStruct/MLEMutator.h \
    3828        ControlStruct/MultiLevelExit.cpp \
    39         ControlStruct/MultiLevelExit.hpp \
    40         ControlStruct/Mutate.cc \
    41         ControlStruct/Mutate.h
     29        ControlStruct/MultiLevelExit.hpp
    4230
  • src/GenPoly/BoxNew.cpp

    r0030b508 rfc12f05  
    3939
    4040namespace {
    41 
    42 /// Common field of several sub-passes of box.
    43 struct BoxPass {
    44         TypeVarMap scopeTypeVars;
    45         BoxPass() : scopeTypeVars( ast::TypeData() ) {}
    46 };
    47 
    48 // TODO: Could this be a common helper somewhere?
    49 ast::FunctionType * makeFunctionType( ast::FunctionDecl const * decl ) {
    50         ast::FunctionType * type = new ast::FunctionType(
    51                 decl->type->isVarArgs, decl->type->qualifiers
    52         );
    53         for ( auto type_param : decl->type_params ) {
    54                 type->forall.emplace_back( new ast::TypeInstType( type_param ) );
    55         }
    56         for ( auto assertion : decl->assertions ) {
    57                 type->assertions.emplace_back( new ast::VariableExpr(
    58                         assertion->location, assertion ) );
    59         }
    60         for ( auto param : decl->params ) {
    61                 type->params.emplace_back( param->get_type() );
    62         }
    63         for ( auto retval : decl->returns ) {
    64                 type->returns.emplace_back( retval->get_type() );
    65         }
    66         return type;
    67 }
    6841
    6942// --------------------------------------------------------------------------
     
    359332/// * Adds appropriate type variables to the function calls.
    360333struct CallAdapter final :
    361                 public BoxPass,
    362334                public ast::WithConstTypeSubstitution,
    363335                public ast::WithGuards,
     
    376348        ast::Expr const * postvisit( ast::AddressExpr const * expr );
    377349        ast::ReturnStmt const * previsit( ast::ReturnStmt const * stmt );
    378         void previsit( ast::PointerType const * type );
    379         void previsit( ast::FunctionType const * type );
    380350
    381351        void beginScope();
     
    440410                CodeLocation const & location, ast::Type const * type );
    441411
    442         /// Set of adapter functions in the current scope.
     412        TypeVarMap scopeTypeVars;
    443413        ScopedMap< std::string, ast::DeclWithType const * > adapters;
    444414        std::map< ast::ApplicationExpr const *, ast::Expr const * > retVals;
     
    553523
    554524ast::FunctionDecl const * CallAdapter::previsit( ast::FunctionDecl const * decl ) {
     525        // Prevent type declaration information from leaking out.
     526        GuardScope( scopeTypeVars );
     527
    555528        if ( nullptr == decl->stmts ) {
    556                 // This may keep TypeDecls we don't ever want from sneaking in.
    557                 // Not visiting child nodes might just be faster.
    558                 GuardScope( scopeTypeVars );
    559529                return decl;
    560530        }
    561531
    562         GuardScope( scopeTypeVars );
    563532        GuardValue( retval );
    564533
     
    662631        ptrdiff_t initArgCount = mutExpr->args.size();
    663632
    664         TypeVarMap exprTypeVars = { ast::TypeData() };
     633        TypeVarMap exprTypeVars;
    665634        // TODO: Should this take into account the variables already bound in
    666635        // scopeTypeVars ([ex] remove them from exprTypeVars)?
     
    687656
    688657        assert( typeSubs );
    689         ast::Type const * concRetType = replaceWithConcrete( dynRetType, *typeSubs );
    690         // Used to use dynRetType instead of concRetType; this changed so that
    691         // the correct type parameters are passed for return types (it should be
    692         // the concrete type's parameters, not the formal type's).
    693658        ast::vector<ast::Expr>::iterator argIt =
    694659                passTypeVars( mutExpr, function );
     
    768733        }
    769734        return stmt;
    770 }
    771 
    772 void CallAdapter::previsit( ast::PointerType const * type ) {
    773         GuardScope( scopeTypeVars );
    774         makeTypeVarMap( type, scopeTypeVars );
    775 }
    776 
    777 void CallAdapter::previsit( ast::FunctionType const * type ) {
    778         GuardScope( scopeTypeVars );
    779         makeTypeVarMap( type, scopeTypeVars );
    780735}
    781736
     
    14271382
    14281383ast::FunctionDecl const * DeclAdapter::previsit( ast::FunctionDecl const * decl ) {
    1429         TypeVarMap localTypeVars = { ast::TypeData() };
     1384        TypeVarMap localTypeVars;
    14301385        makeTypeVarMap( decl, localTypeVars );
    14311386
     
    14581413                        layoutParams.emplace_back( alignParam );
    14591414                }
    1460                 // TODO: These should possibly all be gone.
    1461                 // More all assertions into parameter list.
    1462                 for ( ast::ptr<ast::DeclWithType> & assert : mutParam->assertions ) {
    1463                         // Assertion parameters may not be used in body,
    1464                         // pass along with unused attribute.
    1465                         assert.get_and_mutate()->attributes.push_back(
    1466                                 new ast::Attribute( "unused" ) );
    1467                         inferredParams.push_back( assert );
    1468                 }
    1469                 mutParam->assertions.clear();
     1415                // Assertions should be stored in the main list.
     1416                assert( mutParam->assertions.empty() );
    14701417                typeParam = mutParam;
    14711418        }
    1472         // TODO: New version of inner loop.
    14731419        for ( ast::ptr<ast::DeclWithType> & assert : mutDecl->assertions ) {
    14741420                // Assertion parameters may not be used in body,
     
    14851431        spliceBegin( mutDecl->params, layoutParams );
    14861432        addAdapters( mutDecl, localTypeVars );
     1433
     1434        // Now have to update the type to match the declaration.
     1435        ast::FunctionType * type = new ast::FunctionType(
     1436                mutDecl->type->isVarArgs, mutDecl->type->qualifiers );
     1437        for ( auto type_param : mutDecl->type_params ) {
     1438                type->forall.emplace_back( new ast::TypeInstType( type_param ) );
     1439        }
     1440        for ( auto param : mutDecl->params ) {
     1441                type->params.emplace_back( param->get_type() );
     1442        }
     1443        for ( auto retval : mutDecl->returns ) {
     1444                type->returns.emplace_back( retval->get_type() );
     1445        }
     1446        mutDecl->type = type;
    14871447
    14881448        return mutDecl;
     
    15181478                }
    15191479        }
    1520         // TODO: Can this be updated as we go along?
    1521         mutDecl->type = makeFunctionType( mutDecl );
    15221480        return mutDecl;
    15231481}
     
    15751533        assertf( it != adapters.end(), "Could not correct floating node." );
    15761534        return ast::mutate_field( expr, &ast::VariableExpr::var, it->second );
    1577 
    15781535}
    15791536
     
    15871544/// * Inserts dynamic calculation of polymorphic type layouts where needed.
    15881545struct PolyGenericCalculator final :
    1589                 public BoxPass,
    15901546                public ast::WithConstTypeSubstitution,
    15911547                public ast::WithDeclsToAdd<>,
     
    15951551        PolyGenericCalculator();
    15961552
    1597         void previsit( ast::ObjectDecl const * decl );
    15981553        void previsit( ast::FunctionDecl const * decl );
    15991554        void previsit( ast::TypedefDecl const * decl );
     
    16021557        ast::StructDecl const * previsit( ast::StructDecl const * decl );
    16031558        ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
    1604         void previsit( ast::PointerType const * type );
    1605         void previsit( ast::FunctionType const * type );
    16061559        ast::DeclStmt const * previsit( ast::DeclStmt const * stmt );
    16071560        ast::Expr const * postvisit( ast::MemberExpr const * expr );
     
    16351588        /// C sizeof().
    16361589        ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
    1637 
    16381590        /// Enters a new scope for type-variables,
    16391591        /// adding the type variables from the provided type.
    16401592        void beginTypeScope( ast::Type const * );
    1641         /// Enters a new scope for known layouts and offsets, and queues exit calls.
    1642         void beginGenericScope();
    1643 
     1593
     1594        /// The type variables and polymorphic parameters currently in scope.
     1595        TypeVarMap scopeTypeVars;
    16441596        /// Set of generic type layouts known in the current scope,
    16451597        /// indexed by sizeofName.
     
    16521604        /// If the argument of an AddressExpr is MemberExpr, it is stored here.
    16531605        ast::MemberExpr const * addrMember = nullptr;
    1654         /// Used to avoid recursing too deep in type declarations.
    1655         bool expect_func_type = false;
    16561606};
    16571607
     
    16751625}
    16761626
    1677 void PolyGenericCalculator::previsit( ast::ObjectDecl const * decl ) {
    1678         beginTypeScope( decl->type );
    1679 }
    1680 
    16811627void PolyGenericCalculator::previsit( ast::FunctionDecl const * decl ) {
    1682         beginGenericScope();
     1628        GuardScope( *this );
    16831629        beginTypeScope( decl->type );
    16841630}
     
    16961642                ast::TypeDecl const * decl ) {
    16971643        ast::Type const * base = decl->base;
    1698         if ( nullptr == base) return decl;
     1644        if ( nullptr == base ) return decl;
    16991645
    17001646        // Add size/align variables for opaque type declarations.
     
    17211667        alignDecl->accept( *visitor );
    17221668
    1723         // Can't use [makeVar], because it inserts into stmtsToAdd and TypeDecls
    1724         // can occur at global scope.
     1669        // A little trick to replace this with two declarations.
     1670        // Adding after makes sure that there is no conflict with adding stmts.
    17251671        declsToAddAfter.push_back( alignDecl );
    1726         // replace with sizeDecl.
    17271672        return sizeDecl;
    17281673}
     
    17421687}
    17431688
    1744 void PolyGenericCalculator::previsit( ast::PointerType const * type ) {
    1745         beginTypeScope( type );
    1746 }
    1747 
    1748 void PolyGenericCalculator::previsit( ast::FunctionType const * type ) {
    1749         beginTypeScope( type );
    1750 
    1751         GuardValue( expect_func_type );
    1752         GuardScope( *this );
    1753 
    1754         // The other functions type we will see in this scope are probably
    1755         // function parameters they don't help us with the layout and offsets so
    1756         // don't mark them as known in this scope.
    1757         expect_func_type = false;
    1758 }
    1759 
    1760 //void PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
    17611689ast::DeclStmt const * PolyGenericCalculator::previsit( ast::DeclStmt const * stmt ) {
    17621690        ast::ObjectDecl const * decl = stmt->decl.as<ast::ObjectDecl>();
     
    17661694
    17671695        // Change initialization of a polymorphic value object to allocate via a
    1768         // variable-length-array (alloca was previouly used, but it cannot be
    1769         // safely used in loops).
     1696        // variable-length-array (alloca cannot be safely used in loops).
    17701697        ast::ObjectDecl * newBuf = new ast::ObjectDecl( decl->location,
    17711698                bufNamer.newName(),
     
    22482175}
    22492176
    2250 void PolyGenericCalculator::beginGenericScope() {
    2251         GuardScope( *this );
    2252         // We expect the first function type see to be the type relating to this
    2253         // scope but any further type is probably some unrelated function pointer
    2254         // keep track of whrich is the first.
    2255         GuardValue( expect_func_type ) = true;
    2256 }
    2257 
    22582177// --------------------------------------------------------------------------
    2259 /// No common theme found.
     2178/// Removes unneeded or incorrect type information.
    22602179/// * Replaces initialization of polymorphic values with alloca.
    22612180/// * Replaces declaration of dtype/ftype with appropriate void expression.
     
    22632182/// * Strips fields from generic structure declarations.
    22642183struct Eraser final :
    2265                 public BoxPass,
    22662184                public ast::WithGuards {
    22672185        void guardTypeVarMap( ast::Type const * type ) {
     
    22782196        void previsit( ast::PointerType const * type );
    22792197        void previsit( ast::FunctionType const * type );
     2198public:
     2199        TypeVarMap scopeTypeVars;
    22802200};
    22812201
  • src/GenPoly/FindFunction.cc

    r0030b508 rfc12f05  
    2020#include "AST/Pass.hpp"                 // for Pass
    2121#include "AST/Type.hpp"
    22 #include "Common/PassVisitor.h"         // for PassVisitor
    2322#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::iterator
    2423#include "GenPoly/GenPoly.h"            // for TyVarMap
    2524#include "ScrubTyVars.h"                // for ScrubTyVars
    26 #include "SynTree/Declaration.h"        // for DeclarationWithType, TypeDecl
    27 #include "SynTree/Mutator.h"            // for Mutator, mutateAll
    28 #include "SynTree/Type.h"               // for FunctionType, Type, Type::For...
    2925
    3026namespace GenPoly {
    31         class FindFunction : public WithGuards, public WithVisitorRef<FindFunction>, public WithShortCircuiting {
    32           public:
    33                 FindFunction( std::list< FunctionType const* > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate );
    34 
    35                 void premutate( FunctionType * functionType );
    36                 Type * postmutate( FunctionType * functionType );
    37                 void premutate( PointerType * pointerType );
    38           private:
    39                 void handleForall( const Type::ForallList &forall );
    40 
    41                 std::list< FunctionType const * > & functions;
    42                 TyVarMap tyVars;
    43                 bool replaceMode;
    44                 FindFunctionPredicate predicate;
    45         };
    46 
    47         void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    48                 PassVisitor<FindFunction> finder( functions, tyVars, false, predicate );
    49                 type->acceptMutator( finder );
    50         }
    51 
    52         void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate ) {
    53                 PassVisitor<FindFunction> finder( functions, tyVars, true, predicate );
    54                 type = type->acceptMutator( finder );
    55         }
    56 
    57         FindFunction::FindFunction( std::list< FunctionType const * > &functions, const TyVarMap &tyVars, bool replaceMode, FindFunctionPredicate predicate )
    58                 : functions( functions ), tyVars( tyVars ), replaceMode( replaceMode ), predicate( predicate ) {
    59         }
    60 
    61         void FindFunction::handleForall( const Type::ForallList &forall ) {
    62                 for ( const Declaration * td : forall ) {
    63                         TyVarMap::iterator var = tyVars.find( td->name );
    64                         if ( var != tyVars.end() ) {
    65                                 tyVars.erase( var->first );
    66                         } // if
    67                 } // for
    68         }
    69 
    70         void FindFunction::premutate( FunctionType * functionType ) {
    71                 visit_children = false;
    72                 GuardScope( tyVars );
    73                 handleForall( functionType->get_forall() );
    74                 mutateAll( functionType->get_returnVals(), *visitor );
    75         }
    76 
    77         Type * FindFunction::postmutate( FunctionType * functionType ) {
    78                 Type *ret = functionType;
    79                 if ( predicate( functionType, tyVars ) ) {
    80                         functions.push_back( functionType );
    81                         if ( replaceMode ) {
    82                                 // replace type parameters in function type with void*
    83                                 ret = ScrubTyVars::scrub( functionType->clone(), tyVars );
    84                         } // if
    85                 } // if
    86                 return ret;
    87         }
    88 
    89         void FindFunction::premutate( PointerType * pointerType ) {
    90                 GuardScope( tyVars );
    91                 handleForall( pointerType->get_forall() );
    92         }
    9327
    9428namespace {
     
    15488void FindFunctionCore::previsit( ast::PointerType const * /*type*/ ) {
    15589        GuardScope( typeVars );
    156         //handleForall( type->forall );
    15790}
    15891
     
    16497        ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, false );
    16598        type->accept( pass );
    166         //(void)type;
    167         //(void)functions;
    168         //(void)typeVars;
    169         //(void)predicate;
    17099}
    171100
     
    175104        ast::Pass<FindFunctionCore> pass( functions, typeVars, predicate, true );
    176105        return type->accept( pass );
    177         //(void)functions;
    178         //(void)typeVars;
    179         //(void)predicate;
    180         //return type;
    181106}
    182107
  • src/GenPoly/FindFunction.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include <list>       // for list
    19 
    2018#include "GenPoly.h"  // for TyVarMap
    2119
    22 class FunctionType;
    23 class Type;
    24 
    2520namespace GenPoly {
    26         typedef bool (*FindFunctionPredicate)( FunctionType*, const TyVarMap& );
    27 
    28         /// recursively walk `type`, placing all functions that match `predicate` under `tyVars` into `functions`
    29         void findFunction( Type *type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    30         /// like `findFunction`, but also replaces the function type with void ()(void)
    31         void findAndReplaceFunction( Type *&type, std::list< FunctionType const * > &functions, const TyVarMap &tyVars, FindFunctionPredicate predicate );
    3221
    3322typedef bool (*FindFunctionPred)( const ast::FunctionType *, const TypeVarMap & );
  • src/GenPoly/GenPoly.cc

    r0030b508 rfc12f05  
    2929#include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::const_it...
    3030#include "ResolvExpr/typeops.h"         // for flatten
    31 #include "SynTree/Constant.h"           // for Constant
    32 #include "SynTree/Expression.h"         // for Expression, TypeExpr, Constan...
    33 #include "SynTree/Type.h"               // for Type, StructInstType, UnionIn...
    34 #include "SynTree/TypeSubstitution.h"   // for TypeSubstitution
    3531
    3632using namespace std;
     
    3935        namespace {
    4036                /// Checks a parameter list for polymorphic parameters; will substitute according to env if present
    41                 bool hasPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {
    42                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    43                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    44                                 assertf(paramType, "Aggregate parameters should be type expressions");
    45                                 if ( isPolyType( paramType->get_type(), env ) ) return true;
    46                         }
    47                         return false;
    48                 }
    49 
    5037                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) {
    5138                        for ( auto &param : params ) {
     
    5845
    5946                /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present
    60                 bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    61                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    62                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    63                                 assertf(paramType, "Aggregate parameters should be type expressions");
    64                                 if ( isPolyType( paramType->get_type(), tyVars, env ) ) return true;
    65                         }
    66                         return false;
    67                 }
    68 
    6947                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) {
    7048                        for ( auto & param : params ) {
     
    7755
    7856                /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present
    79                 bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    80                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    81                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    82                                 assertf(paramType, "Aggregate parameters should be type expressions");
    83                                 if ( isDynType( paramType->get_type(), tyVars, env ) ) return true;
    84                         }
    85                         return false;
    86                 }
    87 
    8857                bool hasDynParams(
    8958                                const std::vector<ast::ptr<ast::Expr>> & params,
     
    9968                        return false;
    10069                }
    101 
    102                 /// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present
    103                 bool includesPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {
    104                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    105                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    106                                 assertf(paramType, "Aggregate parameters should be type expressions");
    107                                 if ( includesPolyType( paramType->get_type(), env ) ) return true;
    108                         }
    109                         return false;
    110                 }
    111 
    112                 /// Checks a parameter list for inclusion of polymorphic parameters from tyVars; will substitute according to env if present
    113                 bool includesPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    114                         for ( std::list< Expression* >::iterator param = params.begin(); param != params.end(); ++param ) {
    115                                 TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
    116                                 assertf(paramType, "Aggregate parameters should be type expressions");
    117                                 if ( includesPolyType( paramType->get_type(), tyVars, env ) ) return true;
    118                         }
    119                         return false;
    120                 }
    121         }
    122 
    123         Type* replaceTypeInst( Type* type, const TypeSubstitution* env ) {
    124                 if ( ! env ) return type;
    125                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {
    126                         Type *newType = env->lookup( typeInst->get_name() );
    127                         if ( newType ) return newType;
    128                 }
    129                 return type;
    130         }
    131 
    132         const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env ) {
    133                 if ( ! env ) return type;
    134                 if ( auto typeInst = dynamic_cast< const TypeInstType* >( type ) ) {
    135                         Type *newType = env->lookup( typeInst->get_name() );
    136                         if ( newType ) return newType;
    137                 }
    138                 return type;
    13970        }
    14071
     
    14677                }
    14778                return type;
    148         }
    149 
    150         Type *isPolyType( Type *type, const TypeSubstitution *env ) {
    151                 type = replaceTypeInst( type, env );
    152 
    153                 if ( dynamic_cast< TypeInstType * >( type ) ) {
    154                         return type;
    155                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    156                         return isPolyType( arrayType->base, env );
    157                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    158                         if ( hasPolyParams( structType->get_parameters(), env ) ) return type;
    159                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    160                         if ( hasPolyParams( unionType->get_parameters(), env ) ) return type;
    161                 }
    162                 return 0;
    16379        }
    16480
     
    17894        }
    17995
    180         Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    181                 type = replaceTypeInst( type, env );
    182 
    183                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    184                         if ( tyVars.contains( typeInst->get_name() ) ) {
    185                                 return type;
    186                         }
    187                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    188                         return isPolyType( arrayType->base, tyVars, env );
    189                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    190                         if ( hasPolyParams( structType->get_parameters(), tyVars, env ) ) return type;
    191                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    192                         if ( hasPolyParams( unionType->get_parameters(), tyVars, env ) ) return type;
    193                 }
    194                 return 0;
    195         }
    196 
    19796const ast::Type * isPolyType( const ast::Type * type,
    19897                const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
     
    211110}
    212111
    213         ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    214                 type = replaceTypeInst( type, env );
    215 
    216                 if ( TypeInstType *typeInst = dynamic_cast< TypeInstType * >( type ) ) {
    217                         auto var = tyVars.find( typeInst->get_name() );
    218                         if ( var != tyVars.end() && var->second.isComplete ) {
    219                                 return typeInst;
    220                         }
    221                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    222                         if ( hasDynParams( structType->get_parameters(), tyVars, env ) ) return structType;
    223                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    224                         if ( hasDynParams( unionType->get_parameters(), tyVars, env ) ) return unionType;
    225                 }
    226                 return 0;
    227         }
    228 
    229112const ast::BaseInstType * isDynType(
    230113                const ast::Type * type, const TypeVarMap & typeVars,
     
    249132}
    250133
    251         ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &forallTypes ) {
    252                 if ( function->get_returnVals().empty() ) return 0;
    253 
    254                 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
    255         }
    256 
    257134const ast::BaseInstType *isDynRet(
    258135                const ast::FunctionType * type, const TypeVarMap & typeVars ) {
     
    262139}
    263140
    264         ReferenceToType *isDynRet( FunctionType *function ) {
    265                 if ( function->get_returnVals().empty() ) return 0;
    266 
    267                 TyVarMap forallTypes( TypeDecl::Data{} );
    268                 makeTyVarMap( function, forallTypes );
    269                 return (ReferenceToType*)isDynType( function->get_returnVals().front()->get_type(), forallTypes );
    270         }
    271 
    272141const ast::BaseInstType *isDynRet( const ast::FunctionType * func ) {
    273142        if ( func->returns.empty() ) return nullptr;
    274143
    275         TypeVarMap forallTypes = { ast::TypeData() };
     144        TypeVarMap forallTypes;
    276145        makeTypeVarMap( func, forallTypes );
    277146        return isDynType( func->returns.front(), forallTypes );
    278147}
    279 
    280         bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVars ) {
    281 //              if ( ! adaptee->get_returnVals().empty() && isPolyType( adaptee->get_returnVals().front()->get_type(), tyVars ) ) {
    282 //                      return true;
    283 //              } // if
    284                 if ( isDynRet( adaptee, tyVars ) ) return true;
    285 
    286                 for ( std::list< DeclarationWithType* >::const_iterator innerArg = adaptee->get_parameters().begin(); innerArg != adaptee->get_parameters().end(); ++innerArg ) {
    287 //                      if ( isPolyType( (*innerArg)->get_type(), tyVars ) ) {
    288                         if ( isDynType( (*innerArg)->get_type(), tyVars ) ) {
    289                                 return true;
    290                         } // if
    291                 } // for
    292                 return false;
    293         }
    294148
    295149bool needsAdapter(
     
    304158        return false;
    305159}
    306 
    307         Type *isPolyPtr( Type *type, const TypeSubstitution *env ) {
    308                 type = replaceTypeInst( type, env );
    309 
    310                 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    311                         return isPolyType( ptr->get_base(), env );
    312                 }
    313                 return 0;
    314         }
    315 
    316         Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    317                 type = replaceTypeInst( type, env );
    318 
    319                 if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    320                         return isPolyType( ptr->get_base(), tyVars, env );
    321                 }
    322                 return 0;
    323         }
    324160
    325161const ast::Type * isPolyPtr(
     
    333169        return nullptr;
    334170}
    335 
    336         Type * hasPolyBase( Type *type, int *levels, const TypeSubstitution *env ) {
    337                 int dummy;
    338                 if ( ! levels ) { levels = &dummy; }
    339                 *levels = 0;
    340 
    341                 while ( true ) {
    342                         type = replaceTypeInst( type, env );
    343 
    344                         if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    345                                 type = ptr->get_base();
    346                                 ++(*levels);
    347                         } else break;
    348                 }
    349 
    350                 return isPolyType( type, env );
    351         }
    352 
    353         Type * hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels, const TypeSubstitution *env ) {
    354                 int dummy;
    355                 if ( ! levels ) { levels = &dummy; }
    356                 *levels = 0;
    357 
    358                 while ( true ) {
    359                         type = replaceTypeInst( type, env );
    360 
    361                         if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
    362                                 type = ptr->get_base();
    363                                 ++(*levels);
    364                         } else break;
    365                 }
    366 
    367                 return isPolyType( type, tyVars, env );
    368         }
    369171
    370172ast::Type const * hasPolyBase(
     
    388190}
    389191
    390         bool includesPolyType( Type *type, const TypeSubstitution *env ) {
    391                 type = replaceTypeInst( type, env );
    392 
    393                 if ( dynamic_cast< TypeInstType * >( type ) ) {
    394                         return true;
    395                 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {
    396                         if ( includesPolyType( pointerType->get_base(), env ) ) return true;
    397                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    398                         if ( includesPolyParams( structType->get_parameters(), env ) ) return true;
    399                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    400                         if ( includesPolyParams( unionType->get_parameters(), env ) ) return true;
    401                 }
    402                 return false;
    403         }
    404 
    405         bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    406                 type = replaceTypeInst( type, env );
    407 
    408                 if ( TypeInstType *typeInstType = dynamic_cast< TypeInstType * >( type ) ) {
    409                         if ( tyVars.contains( typeInstType->get_name() ) ) {
    410                                 return true;
    411                         }
    412                 } else if ( PointerType *pointerType = dynamic_cast< PointerType* >( type ) ) {
    413                         if ( includesPolyType( pointerType->get_base(), tyVars, env ) ) return true;
    414                 } else if ( StructInstType *structType = dynamic_cast< StructInstType* >( type ) ) {
    415                         if ( includesPolyParams( structType->get_parameters(), tyVars, env ) ) return true;
    416                 } else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( type ) ) {
    417                         if ( includesPolyParams( unionType->get_parameters(), tyVars, env ) ) return true;
    418                 }
    419                 return false;
    420         }
    421 
    422         FunctionType * getFunctionType( Type *ty ) {
    423                 PointerType *ptrType;
    424                 if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) {
    425                         return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise
    426                 } else {
    427                         return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise
    428                 }
    429         }
    430 
    431192        const ast::FunctionType * getFunctionType( const ast::Type * ty ) {
    432193                if ( auto pty = dynamic_cast< const ast::PointerType * >( ty ) ) {
     
    437198        }
    438199
    439         VariableExpr * getBaseVar( Expression *expr, int *levels ) {
    440                 int dummy;
    441                 if ( ! levels ) { levels = &dummy; }
    442                 *levels = 0;
    443 
    444                 while ( true ) {
    445                         if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) {
    446                                 return varExpr;
    447                         } else if ( MemberExpr *memberExpr = dynamic_cast< MemberExpr* >( expr ) ) {
    448                                 expr = memberExpr->get_aggregate();
    449                         } else if ( AddressExpr *addressExpr = dynamic_cast< AddressExpr* >( expr ) ) {
    450                                 expr = addressExpr->get_arg();
    451                         } else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) {
    452                                 // look for compiler-inserted dereference operator
    453                                 NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() );
    454                                 if ( ! fn || fn->get_name() != std::string("*?") ) return 0;
    455                                 expr = *untypedExpr->begin_args();
    456                         } else if ( CommaExpr *commaExpr = dynamic_cast< CommaExpr* >( expr ) ) {
    457                                 // copy constructors insert comma exprs, look at second argument which contains the variable
    458                                 expr = commaExpr->get_arg2();
    459                                 continue;
    460                         } else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( expr ) ) {
    461                                 int lvl1;
    462                                 int lvl2;
    463                                 VariableExpr * var1 = getBaseVar( condExpr->get_arg2(), &lvl1 );
    464                                 VariableExpr * var2 = getBaseVar( condExpr->get_arg3(), &lvl2 );
    465                                 if ( lvl1 == lvl2 && var1 && var2 && var1->get_var() == var2->get_var() ) {
    466                                         *levels = lvl1;
    467                                         return var1;
    468                                 }
    469                                 break;
    470                         } else break;
    471 
    472                         ++(*levels);
    473                 }
    474 
    475                 return 0;
    476         }
    477 
    478200        namespace {
    479201                /// Checks if is a pointer to D
     
    488210                inline D const * as( B const * p ) {
    489211                        return reinterpret_cast<D const *>( p );
    490                 }
    491 
    492                 /// Flattens a declaration list
    493                 template<typename Output>
    494                 void flattenList( list< DeclarationWithType* > src, Output out ) {
    495                         for ( DeclarationWithType* decl : src ) {
    496                                 ResolvExpr::flatten( decl->get_type(), out );
    497                         }
    498                 }
    499 
    500                 /// Flattens a list of types
    501                 template<typename Output>
    502                 void flattenList( list< Type* > src, Output out ) {
    503                         for ( Type* ty : src ) {
    504                                 ResolvExpr::flatten( ty, out );
    505                         }
    506212                }
    507213
     
    515221                }
    516222
    517                 /// Checks if two lists of parameters are equal up to polymorphic substitution.
    518                 bool paramListsPolyCompatible( const list< Expression* >& aparams, const list< Expression* >& bparams ) {
    519                         if ( aparams.size() != bparams.size() ) return false;
    520 
    521                         for ( list< Expression* >::const_iterator at = aparams.begin(), bt = bparams.begin();
    522                                         at != aparams.end(); ++at, ++bt ) {
    523                                 TypeExpr *aparam = dynamic_cast< TypeExpr* >(*at);
    524                                 assertf(aparam, "Aggregate parameters should be type expressions");
    525                                 TypeExpr *bparam = dynamic_cast< TypeExpr* >(*bt);
    526                                 assertf(bparam, "Aggregate parameters should be type expressions");
    527 
    528                                 // xxx - might need to let VoidType be a wildcard here too; could have some voids
    529                                 // stuffed in for dtype-statics.
    530                                 // if ( is<VoidType>( aparam->get_type() ) || is<VoidType>( bparam->get_type() ) ) continue;
    531                                 if ( ! typesPolyCompatible( aparam->get_type(), bparam->get_type() ) ) return false;
    532                         }
    533 
    534                         return true;
    535                 }
    536 
    537223                bool paramListsPolyCompatible(
    538224                                std::vector<ast::ptr<ast::Expr>> const & lparams,
     
    559245                        return true;
    560246                }
    561         }
    562 
    563         bool typesPolyCompatible( Type *a, Type *b ) {
    564                 type_index aid{ typeid(*a) };
    565                 // polymorphic types always match
    566                 if ( aid == type_index{typeid(TypeInstType)} ) return true;
    567 
    568                 type_index bid{ typeid(*b) };
    569                 // polymorphic types always match
    570                 if ( bid == type_index{typeid(TypeInstType)} ) return true;
    571 
    572                 // can't match otherwise if different types
    573                 if ( aid != bid ) return false;
    574 
    575                 // recurse through type structure (conditions borrowed from Unify.cc)
    576                 if ( aid == type_index{typeid(BasicType)} ) {
    577                         return as<BasicType>(a)->get_kind() == as<BasicType>(b)->get_kind();
    578                 } else if ( aid == type_index{typeid(PointerType)} ) {
    579                         PointerType *ap = as<PointerType>(a), *bp = as<PointerType>(b);
    580 
    581                         // void pointers should match any other pointer type
    582                         return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )
    583                                 || typesPolyCompatible( ap->get_base(), bp->get_base() );
    584                 } else if ( aid == type_index{typeid(ReferenceType)} ) {
    585                         ReferenceType *ap = as<ReferenceType>(a), *bp = as<ReferenceType>(b);
    586                         return is<VoidType>( ap->get_base() ) || is<VoidType>( bp->get_base() )
    587                                 || typesPolyCompatible( ap->get_base(), bp->get_base() );
    588                 } else if ( aid == type_index{typeid(ArrayType)} ) {
    589                         ArrayType *aa = as<ArrayType>(a), *ba = as<ArrayType>(b);
    590 
    591                         if ( aa->get_isVarLen() ) {
    592                                 if ( ! ba->get_isVarLen() ) return false;
    593                         } else {
    594                                 if ( ba->get_isVarLen() ) return false;
    595 
    596                                 ConstantExpr *ad = dynamic_cast<ConstantExpr*>( aa->get_dimension() );
    597                                 ConstantExpr *bd = dynamic_cast<ConstantExpr*>( ba->get_dimension() );
    598                                 if ( ad && bd
    599                                                 && ad->get_constant()->get_value() != bd->get_constant()->get_value() )
    600                                         return false;
    601                         }
    602 
    603                         return typesPolyCompatible( aa->get_base(), ba->get_base() );
    604                 } else if ( aid == type_index{typeid(FunctionType)} ) {
    605                         FunctionType *af = as<FunctionType>(a), *bf = as<FunctionType>(b);
    606 
    607                         vector<Type*> aparams, bparams;
    608                         flattenList( af->get_parameters(), back_inserter( aparams ) );
    609                         flattenList( bf->get_parameters(), back_inserter( bparams ) );
    610                         if ( aparams.size() != bparams.size() ) return false;
    611 
    612                         vector<Type*> areturns, breturns;
    613                         flattenList( af->get_returnVals(), back_inserter( areturns ) );
    614                         flattenList( bf->get_returnVals(), back_inserter( breturns ) );
    615                         if ( areturns.size() != breturns.size() ) return false;
    616 
    617                         for ( unsigned i = 0; i < aparams.size(); ++i ) {
    618                                 if ( ! typesPolyCompatible( aparams[i], bparams[i] ) ) return false;
    619                         }
    620                         for ( unsigned i = 0; i < areturns.size(); ++i ) {
    621                                 if ( ! typesPolyCompatible( areturns[i], breturns[i] ) ) return false;
    622                         }
    623                         return true;
    624                 } else if ( aid == type_index{typeid(StructInstType)} ) {
    625                         StructInstType *aa = as<StructInstType>(a), *ba = as<StructInstType>(b);
    626 
    627                         if ( aa->get_name() != ba->get_name() ) return false;
    628                         return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );
    629                 } else if ( aid == type_index{typeid(UnionInstType)} ) {
    630                         UnionInstType *aa = as<UnionInstType>(a), *ba = as<UnionInstType>(b);
    631 
    632                         if ( aa->get_name() != ba->get_name() ) return false;
    633                         return paramListsPolyCompatible( aa->get_parameters(), ba->get_parameters() );
    634                 } else if ( aid == type_index{typeid(EnumInstType)} ) {
    635                         return as<EnumInstType>(a)->get_name() == as<EnumInstType>(b)->get_name();
    636                 } else if ( aid == type_index{typeid(TraitInstType)} ) {
    637                         return as<TraitInstType>(a)->get_name() == as<TraitInstType>(b)->get_name();
    638                 } else if ( aid == type_index{typeid(TupleType)} ) {
    639                         TupleType *at = as<TupleType>(a), *bt = as<TupleType>(b);
    640 
    641                         vector<Type*> atypes, btypes;
    642                         flattenList( at->get_types(), back_inserter( atypes ) );
    643                         flattenList( bt->get_types(), back_inserter( btypes ) );
    644                         if ( atypes.size() != btypes.size() ) return false;
    645 
    646                         for ( unsigned i = 0; i < atypes.size(); ++i ) {
    647                                 if ( ! typesPolyCompatible( atypes[i], btypes[i] ) ) return false;
    648                         }
    649                         return true;
    650                 } else return true; // VoidType, VarArgsType, ZeroType & OneType just need the same type
    651247        }
    652248
     
    763359}
    764360
    765         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
    766                 // is parameter is not polymorphic, don't need to box
    767                 if ( ! isPolyType( param, exprTyVars ) ) return false;
    768                 Type * newType = arg->clone();
    769                 if ( env ) env->apply( newType );
    770                 std::unique_ptr<Type> manager( newType );
    771                 // if the argument's type is polymorphic, we don't need to box again!
    772                 return ! isPolyType( newType );
    773         }
    774 
    775361bool needsBoxing( const ast::Type * param, const ast::Type * arg,
    776362                const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
     
    786372        return !isPolyType( newType );
    787373}
    788 
    789         bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
    790                 FunctionType * function = getFunctionType( appExpr->function->result );
    791                 assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->function->result ).c_str() );
    792                 TyVarMap exprTyVars( TypeDecl::Data{} );
    793                 makeTyVarMap( function, exprTyVars );
    794                 return needsBoxing( param, arg, exprTyVars, env );
    795         }
    796374
    797375bool needsBoxing(
     
    801379        const ast::FunctionType * function = getFunctionType( expr->func->result );
    802380        assertf( function, "ApplicationExpr has non-function type: %s", toString( expr->func->result ).c_str() );
    803         TypeVarMap exprTyVars = { ast::TypeData() };
     381        TypeVarMap exprTyVars;
    804382        makeTypeVarMap( function, exprTyVars );
    805383        return needsBoxing( param, arg, exprTyVars, subst );
    806384}
    807385
    808         void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
    809                 tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );
    810         }
    811 
    812386void addToTypeVarMap( const ast::TypeDecl * decl, TypeVarMap & typeVars ) {
    813387        typeVars.insert( ast::TypeEnvKey( decl, 0, 0 ), ast::TypeData( decl ) );
     
    817391        typeVars.insert( ast::TypeEnvKey( *type ), ast::TypeData( type->base ) );
    818392}
    819 
    820         void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {
    821                 for ( Type::ForallList::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {
    822                         assert( *tyVar );
    823                         addToTyVarMap( *tyVar, tyVarMap );
    824                 }
    825                 if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
    826                         makeTyVarMap( pointer->get_base(), tyVarMap );
    827                 }
    828         }
    829393
    830394void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars ) {
     
    846410}
    847411
    848         void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap ) {
    849                 for ( TyVarMap::const_iterator i = tyVarMap.begin(); i != tyVarMap.end(); ++i ) {
    850                         os << i->first << " (" << i->second << ") ";
    851                 } // for
    852                 os << std::endl;
    853         }
    854 
    855412} // namespace GenPoly
    856413
  • src/GenPoly/GenPoly.h

    r0030b508 rfc12f05  
    2323#include "AST/Fwd.hpp"            // for ApplicationExpr, BaseInstType, Func...
    2424#include "SymTab/Mangler.h"       // for Mangler
    25 #include "SynTree/Declaration.h"  // for TypeDecl::Data, AggregateDecl, Type...
    26 #include "SynTree/SynTree.h"      // for Visitor Nodes
    2725
    2826namespace ast {
     
    3230namespace GenPoly {
    3331
    34         typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    35         using TypeVarMap = ErasableScopedMap< ast::TypeEnvKey, ast::TypeData >;
     32        struct TypeVarMap : public ErasableScopedMap<ast::TypeEnvKey, ast::TypeData> {
     33                TypeVarMap() : ErasableScopedMap( ast::TypeData() ) {}
     34        };
    3635
    3736        /// Replaces a TypeInstType by its referrent in the environment, if applicable
    38         Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
    39         const Type* replaceTypeInst( const Type* type, const TypeSubstitution* env );
    4037        const ast::Type * replaceTypeInst( const ast::Type *, const ast::TypeSubstitution * );
    4138
    4239        /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
    43         Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );
    4440        const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr);
    4541
    4642        /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    47         Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    4843        const ast::Type * isPolyType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = nullptr );
    4944
    5045        /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
    51         ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    5246        const ast::BaseInstType *isDynType( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst = 0 );
    5347
    5448        /// true iff function has dynamic-layout return type under the given type variable map
    55         ReferenceToType *isDynRet( FunctionType *function, const TyVarMap &tyVars );
    5649        const ast::BaseInstType *isDynRet( const ast::FunctionType * type, const TypeVarMap & typeVars );
    5750
    5851        /// true iff function has dynamic-layout return type under the type variable map generated from its forall-parameters
    59         ReferenceToType *isDynRet( FunctionType *function );
    6052        const ast::BaseInstType *isDynRet( const ast::FunctionType * func );
    6153
    6254        /// A function needs an adapter if it returns a dynamic-layout value or if any of its parameters have dynamic-layout type
    63         bool needsAdapter( FunctionType *adaptee, const TyVarMap &tyVarr );
    6455        bool needsAdapter( ast::FunctionType const * adaptee, const TypeVarMap & typeVars );
    6556
    66         /// returns polymorphic type if is pointer to polymorphic type, NULL otherwise; will look up substitution in env if provided
    67         Type *isPolyPtr( Type *type, const TypeSubstitution *env = 0 );
    68 
    6957        /// returns polymorphic type if is pointer to polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    70         Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    7158        const ast::Type * isPolyPtr( const ast::Type * type, const TypeVarMap & typeVars, const ast::TypeSubstitution * env = 0 );
    72 
    73         /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type, returns the base type, NULL otherwise;
    74         /// N will be stored in levels, if provided, will look up substitution in env if provided
    75         Type *hasPolyBase( Type *type, int *levels = 0, const TypeSubstitution *env = 0 );
    7659
    7760        /// if the base type (after dereferencing N >= 0 pointers) is a polymorphic type in tyVars, returns the base type, NULL otherwise;
    7861        /// N will be stored in levels, if provided, will look up substitution in env if provided
    79         Type *hasPolyBase( Type *type, const TyVarMap &tyVars, int *levels = 0, const TypeSubstitution *env = 0 );
    8062        const ast::Type * hasPolyBase( const ast::Type * type, const TypeVarMap & typeVars, int * levels = 0, const ast::TypeSubstitution * env = 0 );
    8163
    82         /// true iff this type or some base of this type after dereferencing pointers is either polymorphic or a generic type with at least one
    83         /// polymorphic parameter; will look up substitution in env if provided.
    84         bool includesPolyType( Type *type, const TypeSubstitution *env = 0 );
    85 
    86         /// true iff this type or some base of this type after dereferencing pointers is either polymorphic in tyVars, or a generic type with
    87         /// at least one polymorphic parameter in tyVars; will look up substitution in env if provided.
    88         bool includesPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
    89 
    9064        /// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise
    91         FunctionType *getFunctionType( Type *ty );
    9265        const ast::FunctionType * getFunctionType( const ast::Type * ty );
    9366
    94         /// If expr (after dereferencing N >= 0 pointers) is a variable expression, returns the variable expression, NULL otherwise;
    95         /// N will be stored in levels, if provided
    96         VariableExpr *getBaseVar( Expression *expr, int *levels = 0 );
    97 
    9867        /// true iff types are structurally identical, where TypeInstType's match any type.
    99         bool typesPolyCompatible( Type *aty, Type *bty );
    10068        bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs );
    10169
    10270        /// true if arg requires boxing given exprTyVars
    103         bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
    10471        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TypeVarMap & typeVars, const ast::TypeSubstitution * subst );
    10572
    10673        /// true if arg requires boxing in the call to appExpr
    107         bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
    10874        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * expr, const ast::TypeSubstitution * subst );
    10975
    11076        /// Adds the type variable `tyVar` to `tyVarMap`
    111         void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap );
    11277        void addToTypeVarMap( const ast::TypeDecl * type, TypeVarMap & typeVars );
    11378        void addToTypeVarMap( const ast::TypeInstType * type, TypeVarMap & typeVars );
    11479
    11580        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    116         void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
    11781        void makeTypeVarMap( const ast::Type * type, TypeVarMap & typeVars );
    11882        void makeTypeVarMap( const ast::FunctionDecl * decl, TypeVarMap & typeVars );
    119 
    120         /// Prints type variable map
    121         void printTyVarMap( std::ostream &os, const TyVarMap &tyVarMap );
    122 
    123         /// Gets the mangled name of this type; alias for SymTab::Mangler::mangleType().
    124         inline std::string mangleType( const Type *ty ) { return SymTab::Mangler::mangleType( ty ); }
    12583
    12684        /// Gets the name of the sizeof parameter for the type, given its mangled name
     
    13492
    13593        /// Gets the name of the layout function for a given aggregate type, given its declaration
    136         inline std::string layoutofName( AggregateDecl *decl ) { return std::string( "_layoutof_" ) + decl->get_name(); }
    13794        inline std::string layoutofName( ast::AggregateDecl const * decl ) {
    13895                return std::string( "_layoutof_" ) + decl->name;
  • src/GenPoly/ScrubTyVars.cc

    r0030b508 rfc12f05  
    2121#include "ScrubTyVars.h"
    2222#include "SymTab/Mangler.h"             // for mangleType
    23 #include "SynTree/Declaration.h"        // for TypeDecl, TypeDecl::Data, Typ...
    24 #include "SynTree/Expression.h"         // for Expression (ptr only), NameExpr
    25 #include "SynTree/Mutator.h"            // for Mutator
    26 #include "SynTree/Type.h"               // for PointerType, TypeInstType, Type
    2723
    2824namespace GenPoly {
    29         Type * ScrubTyVars::postmutate( TypeInstType * typeInst ) {
    30                 if ( ! tyVars ) {
    31                         if ( typeInst->get_isFtype() ) {
    32                                 delete typeInst;
    33                                 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
    34                         } else {
    35                                 PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
    36                                 delete typeInst;
    37                                 return ret;
    38                         }
    39                 }
    40 
    41                 TyVarMap::const_iterator tyVar = tyVars->find( typeInst->name );
    42                 if ( tyVar != tyVars->end() ) {
    43                         switch ( tyVar->second.kind ) {
    44                           case TypeDecl::Dtype:
    45                           case TypeDecl::Ttype:
    46                                 {
    47                                         PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
    48                                         delete typeInst;
    49                                         return ret;
    50                                 }
    51                           case TypeDecl::Ftype:
    52                                 delete typeInst;
    53                                 return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
    54                           default:
    55                                 assertf(false, "Unhandled tyvar kind: %d", tyVar->second.kind);
    56                         } // switch
    57                 } // if
    58                 return typeInst;
    59         }
    60 
    61         Type * ScrubTyVars::mutateAggregateType( Type * ty ) {
    62                 if ( shouldScrub( ty ) ) {
    63                         PointerType * ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );
    64                         delete ty;
    65                         return ret;
    66                 }
    67                 return ty;
    68         }
    69 
    70         Type * ScrubTyVars::postmutate( StructInstType * structInst ) {
    71                 return mutateAggregateType( structInst );
    72         }
    73 
    74         Type * ScrubTyVars::postmutate( UnionInstType * unionInst ) {
    75                 return mutateAggregateType( unionInst );
    76         }
    77 
    78         void ScrubTyVars::primeBaseScrub( Type * type ) {
    79                 // need to determine whether type needs to be scrubbed to determine whether
    80                 // automatic recursion is necessary
    81                 if ( Type * t = shouldScrub( type ) ) {
    82                         visit_children = false;
    83                         GuardValue( dynType );
    84                         dynType = t;
    85                 }
    86         }
    87 
    88         Expression * ScrubTyVars::postmutate( SizeofExpr * szeof ) {
    89                 // sizeof( T ) => _sizeof_T parameter, which is the size of T
    90                 if ( dynType ) {
    91                         Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) );
    92                         return expr;
    93                 } // if
    94                 return szeof;
    95         }
    96 
    97         Expression * ScrubTyVars::postmutate( AlignofExpr * algnof ) {
    98                 // alignof( T ) => _alignof_T parameter, which is the alignment of T
    99                 if ( dynType ) {
    100                         Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) );
    101                         return expr;
    102                 } // if
    103                 return algnof;
    104         }
    105 
    106         Type * ScrubTyVars::postmutate( PointerType * pointer ) {
    107                 if ( dynType ) {
    108                         Type * ret = dynType->acceptMutator( *visitor );
    109                         ret->get_qualifiers() |= pointer->get_qualifiers();
    110                         pointer->base = nullptr;
    111                         delete pointer;
    112                         return ret;
    113                 }
    114                 return pointer;
    115         }
    11625
    11726namespace {
  • src/GenPoly/ScrubTyVars.h

    r0030b508 rfc12f05  
    1919
    2020#include "AST/Fwd.hpp"        // for Node
    21 #include "Common/PassVisitor.h"
    2221#include "GenPoly.h"          // for TyVarMap, isPolyType, isDynType
    23 #include "SynTree/Mutator.h"  // for Mutator
    24 #include "SynTree/Type.h"     // for Type (ptr only), PointerType (ptr only)
    25 
    26 class AlignofExpr;
    27 class Expression;
    28 class SizeofExpr;
    2922
    3023namespace GenPoly {
    31         struct ScrubTyVars : public WithVisitorRef<ScrubTyVars>, public WithShortCircuiting, public WithGuards {
    32                 /// Whether to scrub all type variables from the provided map, dynamic type variables from the provided map, or all type variables
    33                 enum ScrubMode { FromMap, DynamicFromMap, All };
    34 
    35                 ScrubTyVars() : tyVars(nullptr), mode( All ) {}
    36 
    37                 ScrubTyVars( const TyVarMap &tyVars, ScrubMode mode = FromMap ): tyVars( &tyVars ), mode( mode ) {}
    38 
    39         public:
    40                 /// For all polymorphic types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,
    41                 /// and sizeof/alignof expressions with the proper variable
    42                 template< typename SynTreeClass >
    43                 static SynTreeClass *scrub( SynTreeClass *target, const TyVarMap &tyVars );
    44 
    45                 /// For all dynamic-layout types with type variables in `tyVars`, replaces generic types, dtypes, and ftypes with the appropriate void type,
    46                 /// and sizeof/alignof expressions with the proper variable
    47                 template< typename SynTreeClass >
    48                 static SynTreeClass *scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars );
    49 
    50                 /// For all polymorphic types, replaces generic types, dtypes, and ftypes with the appropriate void type,
    51                 /// and sizeof/alignof expressions with the proper variable
    52                 template< typename SynTreeClass >
    53                 static SynTreeClass *scrubAll( SynTreeClass *target );
    54 
    55                 /// determine if children should be visited based on whether base type should be scrubbed.
    56                 void primeBaseScrub( Type * );
    57 
    58                 void premutate( TypeInstType * ) { visit_children = false; }
    59                 void premutate( StructInstType * ) { visit_children = false; }
    60                 void premutate( UnionInstType * ) { visit_children = false; }
    61                 void premutate( SizeofExpr * szeof ) { primeBaseScrub( szeof->type ); }
    62                 void premutate( AlignofExpr * algnof ) { primeBaseScrub( algnof->type ); }
    63                 void premutate( PointerType * pointer ) { primeBaseScrub( pointer->base ); }
    64 
    65                 Type * postmutate( TypeInstType * typeInst );
    66                 Type * postmutate( StructInstType * structInst );
    67                 Type * postmutate( UnionInstType * unionInst );
    68                 Expression * postmutate( SizeofExpr * szeof );
    69                 Expression * postmutate( AlignofExpr * algnof );
    70                 Type * postmutate( PointerType * pointer );
    71 
    72           private:
    73                 /// Returns the type if it should be scrubbed, NULL otherwise.
    74                 Type* shouldScrub( Type *ty ) {
    75                         switch ( mode ) {
    76                         case FromMap: return isPolyType( ty, *tyVars );
    77                         case DynamicFromMap: return isDynType( ty, *tyVars );
    78                         case All: return isPolyType( ty );
    79                         }
    80                         assert(false); return nullptr; // unreachable
    81                         // return dynamicOnly ? isDynType( ty, tyVars ) : isPolyType( ty, tyVars );
    82                 }
    83 
    84                 /// Mutates (possibly generic) aggregate types appropriately
    85                 Type* mutateAggregateType( Type *ty );
    86 
    87                 const TyVarMap *tyVars;  ///< Type variables to scrub
    88                 ScrubMode mode;          ///< which type variables to scrub? [FromMap]
    89 
    90                 Type * dynType = nullptr; ///< result of shouldScrub
    91         };
    92 
    93         template< typename SynTreeClass >
    94         SynTreeClass * ScrubTyVars::scrub( SynTreeClass *target, const TyVarMap &tyVars ) {
    95                 PassVisitor<ScrubTyVars> scrubber( tyVars );
    96                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    97         }
    98 
    99         template< typename SynTreeClass >
    100         SynTreeClass * ScrubTyVars::scrubDynamic( SynTreeClass *target, const TyVarMap &tyVars ) {
    101                 PassVisitor<ScrubTyVars> scrubber( tyVars, ScrubTyVars::DynamicFromMap );
    102                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    103         }
    104 
    105         template< typename SynTreeClass >
    106         SynTreeClass * ScrubTyVars::scrubAll( SynTreeClass *target ) {
    107                 PassVisitor<ScrubTyVars> scrubber;
    108                 return static_cast< SynTreeClass * >( target->acceptMutator( scrubber ) );
    109         }
    11024
    11125// ScrubMode and scrubTypeVarsBase are internal.
  • src/GenPoly/SpecializeNew.cpp

    r0030b508 rfc12f05  
    2323#include "GenPoly/GenPoly.h"             // for getFunctionType
    2424#include "ResolvExpr/FindOpenVars.h"     // for findOpenVars
    25 #include "ResolvExpr/TypeEnvironment.h"  // for FirstOpen, FirstClosed
    2625
    2726namespace GenPoly {
     
    8180}
    8281
    83 // The number of elements in a type if it is a flattened tuple.
    84 size_t flatTupleSize( const ast::Type * type ) {
    85         if ( auto tuple = dynamic_cast<const ast::TupleType *>( type ) ) {
    86                 size_t sum = 0;
    87                 for ( auto t : *tuple ) {
    88                         sum += flatTupleSize( t );
    89                 }
    90                 return sum;
    91         } else {
    92                 return 1;
    93         }
     82// The number of elements in a list, if all tuples had been flattened.
     83size_t flatTypeListSize( const std::vector<ast::ptr<ast::Type>> & types ) {
     84        size_t sum = 0;
     85        for ( const ast::ptr<ast::Type> & type : types ) {
     86                if ( const ast::TupleType * tuple = type.as<ast::TupleType>() ) {
     87                        sum += flatTypeListSize( tuple->types );
     88                } else {
     89                        sum += 1;
     90                }
     91        }
     92        return sum;
    9493}
    9594
    9695// Find the total number of components in a parameter list.
    9796size_t functionParameterSize( const ast::FunctionType * type ) {
    98         size_t sum = 0;
    99         for ( auto param : type->params ) {
    100                 sum += flatTupleSize( param );
    101         }
    102         return sum;
     97        return flatTypeListSize( type->params );
    10398}
    10499
  • src/GenPoly/module.mk

    r0030b508 rfc12f05  
    2323SRC += $(SRC_GENPOLY) \
    2424        GenPoly/BoxNew.cpp \
    25         GenPoly/Box.cc \
    2625        GenPoly/Box.h \
    2726        GenPoly/ErasableScopedMap.h \
     
    2928        GenPoly/FindFunction.h \
    3029        GenPoly/InstantiateGenericNew.cpp \
    31         GenPoly/InstantiateGeneric.cc \
    3230        GenPoly/InstantiateGeneric.h \
    3331        GenPoly/LvalueNew.cpp \
    34         GenPoly/Lvalue.cc \
    3532        GenPoly/ScopedSet.h \
    3633        GenPoly/ScrubTyVars.cc \
    3734        GenPoly/ScrubTyVars.h \
    38         GenPoly/Specialize.cc \
    3935        GenPoly/SpecializeNew.cpp \
    4036        GenPoly/Specialize.h
  • src/InitTweak/FixGlobalInit.cc

    r0030b508 rfc12f05  
    2020#include <algorithm>               // for replace_if
    2121
    22 #include "Common/PassVisitor.h"
    23 #include "Common/UniqueName.h"     // for UniqueName
    24 #include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
    25 #include "SynTree/LinkageSpec.h"   // for C
    26 #include "SynTree/Attribute.h"     // for Attribute
    27 #include "SynTree/Constant.h"      // for Constant
    28 #include "SynTree/Declaration.h"   // for FunctionDecl, ObjectDecl, Declaration
    29 #include "SynTree/Expression.h"    // for ConstantExpr, Expression (ptr only)
    30 #include "SynTree/Initializer.h"   // for ConstructorInit, Initializer
    31 #include "SynTree/Label.h"         // for Label
    32 #include "SynTree/Statement.h"     // for CompoundStmt, Statement (ptr only)
    33 #include "SynTree/Type.h"          // for Type, Type::StorageClasses, Functi...
    34 #include "SynTree/Visitor.h"       // for acceptAll, Visitor
    35 
    3622#include "AST/Expr.hpp"
    3723#include "AST/Node.hpp"
    3824#include "AST/Pass.hpp"
     25#include "Common/UniqueName.h"     // for UniqueName
     26#include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
    3927
    4028namespace InitTweak {
    41         class GlobalFixer : public WithShortCircuiting {
    42           public:
    43                 GlobalFixer( bool inLibrary );
    44 
    45                 void previsit( ObjectDecl *objDecl );
    46                 void previsit( FunctionDecl *functionDecl );
    47                 void previsit( StructDecl *aggregateDecl );
    48                 void previsit( UnionDecl *aggregateDecl );
    49                 void previsit( EnumDecl *aggregateDecl );
    50                 void previsit( TraitDecl *aggregateDecl );
    51                 void previsit( TypeDecl *typeDecl );
    52 
    53                 UniqueName tempNamer;
    54                 FunctionDecl * initFunction;
    55                 FunctionDecl * destroyFunction;
    56         };
    57 
    5829        class GlobalFixer_new : public ast::WithShortCircuiting {
    5930        public:
     
    6940                std::list< ast::ptr<ast::Stmt> > destroyStmts;
    7041        };
    71 
    72         void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary ) {
    73                 PassVisitor<GlobalFixer> visitor( inLibrary );
    74                 acceptAll( translationUnit, visitor );
    75                 GlobalFixer & fixer = visitor.pass;
    76                 // don't need to include function if it's empty
    77                 if ( fixer.initFunction->get_statements()->get_kids().empty() ) {
    78                         delete fixer.initFunction;
    79                 } else {
    80                         translationUnit.push_back( fixer.initFunction );
    81                 } // if
    82 
    83                 if ( fixer.destroyFunction->get_statements()->get_kids().empty() ) {
    84                         delete fixer.destroyFunction;
    85                 } else {
    86                         translationUnit.push_back( fixer.destroyFunction );
    87                 } // if
    88         }
    89 
    90         GlobalFixer::GlobalFixer( bool inLibrary ) : tempNamer( "_global_init" ) {
    91                 std::list< Expression * > ctorParameters;
    92                 std::list< Expression * > dtorParameters;
    93                 if ( inLibrary ) {
    94                         // Constructor/destructor attributes take a single parameter which
    95                         // is the priority, with lower numbers meaning higher priority.
    96                         // Functions specified with priority are guaranteed to run before
    97                         // functions without a priority. To ensure that constructors and destructors
    98                         // for library code are run before constructors and destructors for user code,
    99                         // specify a priority when building the library. Priorities 0-100 are reserved by gcc.
    100                         // Priorities 101-200 are reserved by cfa, so use priority 200 for CFA library globals,
    101                         // allowing room for overriding with a higher priority.
    102                         ctorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );
    103                         dtorParameters.push_back( new ConstantExpr( Constant::from_int( 200 ) ) );
    104                 }
    105                 initFunction = new FunctionDecl( "__global_init__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );
    106                 initFunction->get_attributes().push_back( new Attribute( "constructor", ctorParameters ) );
    107                 destroyFunction = new FunctionDecl( "__global_destroy__", Type::StorageClasses( Type::Static ), LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt() );
    108                 destroyFunction->get_attributes().push_back( new Attribute( "destructor", dtorParameters ) );
    109         }
    11042
    11143        void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
     
    14173        }
    14274
    143         void GlobalFixer::previsit( ObjectDecl *objDecl ) {
    144                 std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids();
    145                 std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids();
    146 
    147                 // C allows you to initialize objects with constant expressions
    148                 // xxx - this is an optimization. Need to first resolve constructors before we decide
    149                 // to keep C-style initializer.
    150                 // if ( isConstExpr( objDecl->get_init() ) ) return;
    151 
    152                 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
    153                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    154                         assert( ! ctorInit->ctor || ! ctorInit->init );
    155 
    156                         Statement * dtor = ctorInit->dtor;
    157                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    158                                 // don't need to call intrinsic dtor, because it does nothing, but
    159                                 // non-intrinsic dtors must be called
    160                                 destroyStatements.push_front( dtor );
    161                                 ctorInit->dtor = nullptr;
    162                         } // if
    163                         if ( Statement * ctor = ctorInit->ctor ) {
    164                                 addDataSectionAttribute( objDecl );
    165                                 initStatements.push_back( ctor );
    166                                 objDecl->init = nullptr;
    167                                 ctorInit->ctor = nullptr;
    168                         } else if ( Initializer * init = ctorInit->init ) {
    169                                 objDecl->init = init;
    170                                 ctorInit->init = nullptr;
    171                         } else {
    172                                 // no constructor and no initializer, which is okay
    173                                 objDecl->init = nullptr;
    174                         } // if
    175                         delete ctorInit;
    176                 } // if
    177         }
    178 
    17975        void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) {
    18076                auto mutDecl = mutate(objDecl);
     
    207103        }
    208104
    209         // only modify global variables
    210         void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; }
    211         void GlobalFixer::previsit( StructDecl * ) { visit_children = false; }
    212         void GlobalFixer::previsit( UnionDecl * ) { visit_children = false; }
    213         void GlobalFixer::previsit( EnumDecl * ) { visit_children = false; }
    214         void GlobalFixer::previsit( TraitDecl * ) { visit_children = false; }
    215         void GlobalFixer::previsit( TypeDecl * ) { visit_children = false; }
    216 
    217105} // namespace InitTweak
    218106
  • src/InitTweak/FixInitNew.cpp

    r0030b508 rfc12f05  
    3333#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3434
    35 extern bool ctordtorp; // print all debug
    36 extern bool ctorp; // print ctor debug
    37 extern bool cpctorp; // print copy ctor debug
    38 extern bool dtorp; // print dtor debug
     35bool ctordtorp = false; // print all debug
     36bool ctorp = false; // print ctor debug
     37bool cpctorp = false; // print copy ctor debug
     38bool dtorp = false; // print dtor debug
    3939#define PRINT( text ) if ( ctordtorp ) { text }
    4040#define CP_CTOR_PRINT( text ) if ( ctordtorp || cpctorp ) { text }
     
    178178/// (currently by FixInit)
    179179struct InsertDtors final : public ObjDeclCollector, public ast::WithStmtsToAdd<> {
    180         typedef std::list< ObjectDecl * > OrderedDecls;
    181         typedef std::list< OrderedDecls > OrderedDeclsStack;
    182 
    183180        InsertDtors( ast::Pass<LabelFinder> & finder ) : finder( finder ), labelVars( finder.core.vars ) {}
    184181
     
    194191        ast::Pass<LabelFinder> & finder;
    195192        LabelFinder::LabelMap & labelVars;
    196         OrderedDeclsStack reverseDeclOrder;
    197193};
    198194
  • src/InitTweak/GenInit.cc

    r0030b508 rfc12f05  
    2929#include "CompilationState.h"
    3030#include "CodeGen/OperatorTable.h"
    31 #include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
    3231#include "Common/SemanticError.h"      // for SemanticError
    3332#include "Common/ToString.hpp"         // for toCString
     
    3837#include "InitTweak.h"                 // for isConstExpr, InitExpander, checkIn...
    3938#include "ResolvExpr/Resolver.h"
    40 #include "SymTab/Autogen.h"            // for genImplicitCall
    4139#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4240#include "SymTab/Mangler.h"            // for Mangler
    43 #include "SynTree/LinkageSpec.h"       // for isOverridable, C
    44 #include "SynTree/Declaration.h"       // for ObjectDecl, DeclarationWithType
    45 #include "SynTree/Expression.h"        // for VariableExpr, UntypedExpr, Address...
    46 #include "SynTree/Initializer.h"       // for ConstructorInit, SingleInit, Initi...
    47 #include "SynTree/Label.h"             // for Label
    48 #include "SynTree/Mutator.h"           // for mutateAll
    49 #include "SynTree/Statement.h"         // for CompoundStmt, ImplicitCtorDtorStmt
    50 #include "SynTree/Type.h"              // for Type, ArrayType, Type::Qualifiers
    51 #include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
    5241#include "Tuples/Tuples.h"             // for maybeImpure
    5342#include "Validate/FindSpecialDecls.h" // for SizeType
    5443
    5544namespace InitTweak {
    56         namespace {
    57                 const std::list<Label> noLabels;
    58                 const std::list<Expression *> noDesignators;
    59         }
    60 
    61         struct ReturnFixer : public WithStmtsToAdd, public WithGuards {
    62                 /// consistently allocates a temporary variable for the return value
    63                 /// of a function so that anything which the resolver decides can be constructed
    64                 /// into the return type of a function can be returned.
    65                 static void makeReturnTemp( std::list< Declaration * > &translationUnit );
    66 
    67                 void premutate( FunctionDecl *functionDecl );
    68                 void premutate( ReturnStmt * returnStmt );
    69 
    70           protected:
    71                 FunctionType * ftype = nullptr;
    72                 std::string funcName;
    73         };
    74 
    75         struct CtorDtor : public WithGuards, public WithShortCircuiting, public WithVisitorRef<CtorDtor>  {
    76                 /// create constructor and destructor statements for object declarations.
    77                 /// the actual call statements will be added in after the resolver has run
    78                 /// so that the initializer expression is only removed if a constructor is found
    79                 /// and the same destructor call is inserted in all of the appropriate locations.
    80                 static void generateCtorDtor( std::list< Declaration * > &translationUnit );
    81 
    82                 void previsit( ObjectDecl * );
    83                 void previsit( FunctionDecl *functionDecl );
    84 
    85                 // should not traverse into any of these declarations to find objects
    86                 // that need to be constructed or destructed
    87                 void previsit( StructDecl *aggregateDecl );
    88                 void previsit( AggregateDecl * ) { visit_children = false; }
    89                 void previsit( NamedTypeDecl * ) { visit_children = false; }
    90                 void previsit( FunctionType * ) { visit_children = false; }
    91 
    92                 void previsit( CompoundStmt * compoundStmt );
    93 
    94           private:
    95                 // set of mangled type names for which a constructor or destructor exists in the current scope.
    96                 // these types require a ConstructorInit node to be generated, anything else is a POD type and thus
    97                 // should not have a ConstructorInit generated.
    98 
    99                 ManagedTypes managedTypes;
    100                 bool inFunction = false;
    101         };
    102 
    103         struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer {
    104                 /// hoist dimension from array types in object declaration so that it uses a single
    105                 /// const variable of type size_t, so that side effecting array dimensions are only
    106                 /// computed once.
    107                 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
    108 
    109                 void premutate( ObjectDecl * objectDecl );
    110                 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
    111                 void premutate( FunctionDecl *functionDecl );
    112                 // should not traverse into any of these declarations to find objects
    113                 // that need to be constructed or destructed
    114                 void premutate( AggregateDecl * ) { visit_children = false; }
    115                 void premutate( NamedTypeDecl * ) { visit_children = false; }
    116                 void premutate( FunctionType * ) { visit_children = false; }
    117 
    118                 // need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *)
    119                 void premutate( EnumDecl * ) {}
    120 
    121                 void hoist( Type * type );
    122 
    123                 Type::StorageClasses storageClasses;
    124                 bool inFunction = false;
    125         };
    126 
    127         struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
    128                 /// hoist dimension from array types in object declaration so that it uses a single
    129                 /// const variable of type size_t, so that side effecting array dimensions are only
    130                 /// computed once.
    131                 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
    132 
    133                 void premutate( ObjectDecl * objectDecl );
    134                 DeclarationWithType * postmutate( ObjectDecl * objectDecl );
    135                 void premutate( FunctionDecl *functionDecl );
    136                 // should not traverse into any of these declarations to find objects
    137                 // that need to be constructed or destructed
    138                 void premutate( AggregateDecl * ) { visit_children = false; }
    139                 void premutate( NamedTypeDecl * ) { visit_children = false; }
    140                 void premutate( FunctionType * ) { visit_children = false; }
    141 
    142                 void hoist( Type * type );
    143 
    144                 Type::StorageClasses storageClasses;
    145                 bool inFunction = false;
    146         };
    147 
    148         void genInit( std::list< Declaration * > & translationUnit ) {
    149                 if (!useNewAST) {
    150                         HoistArrayDimension::hoistArrayDimension( translationUnit );
    151                 }
    152                 else {
    153                         HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
    154                 }
    155                 fixReturnStatements( translationUnit );
    156 
    157                 if (!useNewAST) {
    158                         CtorDtor::generateCtorDtor( translationUnit );
    159                 }
    160         }
    161 
    162         void fixReturnStatements( std::list< Declaration * > & translationUnit ) {
    163                 PassVisitor<ReturnFixer> fixer;
    164                 mutateAll( translationUnit, fixer );
    165         }
    166 
    167         void ReturnFixer::premutate( ReturnStmt *returnStmt ) {
    168                 std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
    169                 assert( returnVals.size() == 0 || returnVals.size() == 1 );
    170                 // hands off if the function returns a reference - we don't want to allocate a temporary if a variable's address
    171                 // is being returned
    172                 if ( returnStmt->expr && returnVals.size() == 1 && isConstructable( returnVals.front()->get_type() ) ) {
    173                         // explicitly construct the return value using the return expression and the retVal object
    174                         assertf( returnVals.front()->name != "", "Function %s has unnamed return value\n", funcName.c_str() );
    175 
    176                         ObjectDecl * retVal = strict_dynamic_cast< ObjectDecl * >( returnVals.front() );
    177                         if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( returnStmt->expr ) ) {
    178                                 // return statement has already been mutated - don't need to do it again
    179                                 if ( varExpr->var == retVal ) return;
    180                         }
    181                         Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr );
    182                         assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() );
    183                         stmtsToAddBefore.push_back( stmt );
    184 
    185                         // return the retVal object
    186                         returnStmt->expr = new VariableExpr( returnVals.front() );
    187                 } // if
    188         }
    189 
    190         void ReturnFixer::premutate( FunctionDecl *functionDecl ) {
    191                 GuardValue( ftype );
    192                 GuardValue( funcName );
    193 
    194                 ftype = functionDecl->type;
    195                 funcName = functionDecl->name;
    196         }
    197 
    198         // precompute array dimension expression, because constructor generation may duplicate it,
    199         // which would be incorrect if it is a side-effecting computation.
    200         void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    201                 PassVisitor<HoistArrayDimension> hoister;
    202                 mutateAll( translationUnit, hoister );
    203         }
    204 
    205         void HoistArrayDimension::premutate( ObjectDecl * objectDecl ) {
    206                 GuardValue( storageClasses );
    207                 storageClasses = objectDecl->get_storageClasses();
    208         }
    209 
    210         DeclarationWithType * HoistArrayDimension::postmutate( ObjectDecl * objectDecl ) {
    211                 hoist( objectDecl->get_type() );
    212                 return objectDecl;
    213         }
    214 
    215         void HoistArrayDimension::hoist( Type * type ) {
    216                 // if in function, generate const size_t var
    217                 static UniqueName dimensionName( "_array_dim" );
    218 
    219                 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
    220                 if ( ! inFunction ) return;
    221                 if ( storageClasses.is_static ) return;
    222 
    223                 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    224                         if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
    225 
    226                         // need to resolve array dimensions in order to accurately determine if constexpr
    227                         ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
    228                         // array is variable-length when the dimension is not constexpr
    229                         arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
    230                         // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    231                         // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
    232                         // still try to detect constant expressions
    233                         if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    234 
    235                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    236                         arrayDimension->get_type()->set_const( true );
    237 
    238                         arrayType->set_dimension( new VariableExpr( arrayDimension ) );
    239                         declsToAddBefore.push_back( arrayDimension );
    240 
    241                         hoist( arrayType->get_base() );
    242                         return;
    243                 }
    244         }
    245 
    246         void HoistArrayDimension::premutate( FunctionDecl * ) {
    247                 GuardValue( inFunction );
    248                 inFunction = true;
    249         }
    250 
    251         // precompute array dimension expression, because constructor generation may duplicate it,
    252         // which would be incorrect if it is a side-effecting computation.
    253         void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    254                 PassVisitor<HoistArrayDimension_NoResolve> hoister;
    255                 mutateAll( translationUnit, hoister );
    256         }
    257 
    258         void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
    259                 GuardValue( storageClasses );
    260                 storageClasses = objectDecl->get_storageClasses();
    261         }
    262 
    263         DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
    264                 hoist( objectDecl->get_type() );
    265                 return objectDecl;
    266         }
    267 
    268         void HoistArrayDimension_NoResolve::hoist( Type * type ) {
    269                 // if in function, generate const size_t var
    270                 static UniqueName dimensionName( "_array_dim" );
    271 
    272                 // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
    273                 if ( ! inFunction ) return;
    274                 if ( storageClasses.is_static ) return;
    275 
    276                 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    277                         if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
    278                         // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
    279                         // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
    280                         // still try to detect constant expressions
    281                         if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    282 
    283                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    284                         arrayDimension->get_type()->set_const( true );
    285 
    286                         arrayType->set_dimension( new VariableExpr( arrayDimension ) );
    287                         declsToAddBefore.push_back( arrayDimension );
    288 
    289                         hoist( arrayType->get_base() );
    290                         return;
    291                 }
    292         }
    293 
    294         void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
    295                 GuardValue( inFunction );
    296                 inFunction = true;
    297         }
    29845
    29946namespace {
     
    526273        }
    527274
    528         void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
    529                 PassVisitor<CtorDtor> ctordtor;
    530                 acceptAll( translationUnit, ctordtor );
    531         }
    532 
    533         bool ManagedTypes::isManaged( Type * type ) const {
    534                 // references are never constructed
    535                 if ( dynamic_cast< ReferenceType * >( type ) ) return false;
    536                 // need to clear and reset qualifiers when determining if a type is managed
    537                 ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
    538                 type->get_qualifiers() = Type::Qualifiers();
    539                 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
    540                         // tuple is also managed if any of its components are managed
    541                         if ( std::any_of( tupleType->types.begin(), tupleType->types.end(), [&](Type * type) { return isManaged( type ); }) ) {
    542                                 return true;
    543                         }
    544                 }
    545                 // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
    546                 return managedTypes.find( SymTab::Mangler::mangleConcrete( type ) ) != managedTypes.end() || GenPoly::isPolyType( type );
    547         }
    548 
    549         bool ManagedTypes::isManaged( ObjectDecl * objDecl ) const {
    550                 Type * type = objDecl->get_type();
    551                 while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
    552                         // must always construct VLAs with an initializer, since this is an error in C
    553                         if ( at->isVarLen && objDecl->init ) return true;
    554                         type = at->get_base();
    555                 }
    556                 return isManaged( type );
    557         }
    558 
    559         // why is this not just on FunctionDecl?
    560         void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {
    561                 // if this function is a user-defined constructor or destructor, mark down the type as "managed"
    562                 if ( ! LinkageSpec::isOverridable( dwt->get_linkage() ) && CodeGen::isCtorDtor( dwt->get_name() ) ) {
    563                         std::list< DeclarationWithType * > & params = GenPoly::getFunctionType( dwt->get_type() )->get_parameters();
    564                         assert( ! params.empty() );
    565                         Type * type = InitTweak::getPointerBase( params.front()->get_type() );
    566                         assert( type );
    567                         managedTypes.insert( SymTab::Mangler::mangleConcrete( type ) );
    568                 }
    569         }
    570 
    571         void ManagedTypes::handleStruct( StructDecl * aggregateDecl ) {
    572                 // don't construct members, but need to take note if there is a managed member,
    573                 // because that means that this type is also managed
    574                 for ( Declaration * member : aggregateDecl->get_members() ) {
    575                         if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
    576                                 if ( isManaged( field ) ) {
    577                                         // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
    578                                         // polymorphic constructors make generic types managed types
    579                                         StructInstType inst( Type::Qualifiers(), aggregateDecl );
    580                                         managedTypes.insert( SymTab::Mangler::mangleConcrete( &inst ) );
    581                                         break;
    582                                 }
    583                         }
    584                 }
    585         }
    586 
    587         void ManagedTypes::beginScope() { managedTypes.beginScope(); }
    588         void ManagedTypes::endScope() { managedTypes.endScope(); }
    589 
    590275        bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
    591276                // references are never constructed
     
    647332        void ManagedTypes_new::endScope() { managedTypes.endScope(); }
    648333
    649         ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {
    650                 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    651                 assertf( objDecl, "genCtorDtor passed null objDecl" );
    652                 std::list< Statement * > stmts;
    653                 InitExpander_old srcParam( maybeClone( arg ) );
    654                 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), fname, back_inserter( stmts ), objDecl );
    655                 assert( stmts.size() <= 1 );
    656                 return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;
    657 
    658         }
    659 
    660334        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
    661335                assertf(objDecl, "genCtorDtor passed null objDecl");
    662336                InitExpander_new srcParam(arg);
    663337                return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
    664         }
    665 
    666         ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
    667                 // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    668                 // for each constructable object
    669                 std::list< Statement * > ctor;
    670                 std::list< Statement * > dtor;
    671 
    672                 InitExpander_old srcParam( objDecl->get_init() );
    673                 InitExpander_old nullParam( (Initializer *)NULL );
    674                 SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    675                 SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
    676 
    677                 // Currently genImplicitCall produces a single Statement - a CompoundStmt
    678                 // which  wraps everything that needs to happen. As such, it's technically
    679                 // possible to use a Statement ** in the above calls, but this is inherently
    680                 // unsafe, so instead we take the slightly less efficient route, but will be
    681                 // immediately informed if somehow the above assumption is broken. In this case,
    682                 // we could always wrap the list of statements at this point with a CompoundStmt,
    683                 // but it seems reasonable at the moment for this to be done by genImplicitCall
    684                 // itself. It is possible that genImplicitCall produces no statements (e.g. if
    685                 // an array type does not have a dimension). In this case, it's fine to ignore
    686                 // the object for the purposes of construction.
    687                 assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
    688                 if ( ctor.size() == 1 ) {
    689                         // need to remember init expression, in case no ctors exist
    690                         // if ctor does exist, want to use ctor expression instead of init
    691                         // push this decision to the resolver
    692                         assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    693                         return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
    694                 }
    695                 return nullptr;
    696         }
    697 
    698         void CtorDtor::previsit( ObjectDecl * objDecl ) {
    699                 managedTypes.handleDWT( objDecl );
    700                 // hands off if @=, extern, builtin, etc.
    701                 // even if unmanaged, try to construct global or static if initializer is not constexpr, since this is not legal C
    702                 if ( tryConstruct( objDecl ) && ( managedTypes.isManaged( objDecl ) || ((! inFunction || objDecl->get_storageClasses().is_static ) && ! isConstExpr( objDecl->get_init() ) ) ) ) {
    703                         // constructed objects cannot be designated
    704                         if ( isDesignated( objDecl->get_init() ) ) SemanticError( objDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
    705                         // constructed objects should not have initializers nested too deeply
    706                         if ( ! checkInitDepth( objDecl ) ) SemanticError( objDecl, "Managed object's initializer is too deep " );
    707 
    708                         objDecl->set_init( genCtorInit( objDecl ) );
    709                 }
    710         }
    711 
    712         void CtorDtor::previsit( FunctionDecl *functionDecl ) {
    713                 visit_children = false;  // do not try and construct parameters or forall parameters
    714                 GuardValue( inFunction );
    715                 inFunction = true;
    716 
    717                 managedTypes.handleDWT( functionDecl );
    718 
    719                 GuardScope( managedTypes );
    720                 // go through assertions and recursively add seen ctor/dtors
    721                 for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
    722                         for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
    723                                 managedTypes.handleDWT( assertion );
    724                         }
    725                 }
    726 
    727                 maybeAccept( functionDecl->get_statements(), *visitor );
    728         }
    729 
    730         void CtorDtor::previsit( StructDecl *aggregateDecl ) {
    731                 visit_children = false; // do not try to construct and destruct aggregate members
    732 
    733                 managedTypes.handleStruct( aggregateDecl );
    734         }
    735 
    736         void CtorDtor::previsit( CompoundStmt * ) {
    737                 GuardScope( managedTypes );
    738338        }
    739339
  • src/InitTweak/GenInit.h

    r0030b508 rfc12f05  
    2222#include "Common/CodeLocation.h"
    2323#include "GenPoly/ScopedSet.h" // for ScopedSet
    24 #include "SynTree/SynTree.h"   // for Visitor Nodes
    2524
    2625namespace InitTweak {
    2726        /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
    28         void genInit( std::list< Declaration * > & translationUnit );
    2927        void genInit( ast::TranslationUnit & translationUnit );
    3028
    3129        /// Converts return statements into copy constructor calls on the hidden return variable.
    3230        /// This pass must happen before auto-gen.
    33         void fixReturnStatements( std::list< Declaration * > & translationUnit );
    3431        void fixReturnStatements( ast::TranslationUnit & translationUnit );
    3532
    3633        /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
    37         ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr );
    3834        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
    3935
    4036        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
    41         ConstructorInit * genCtorInit( ObjectDecl * objDecl );
    4237        ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
    43 
    44         class ManagedTypes {
    45         public:
    46                 bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed
    47                 bool isManaged( Type * type ) const; // determine if type is managed
    48 
    49                 void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor
    50                 void handleStruct( StructDecl * aggregateDecl ); // add type to managed if child is managed
    51 
    52                 void beginScope();
    53                 void endScope();
    54         private:
    55                 GenPoly::ScopedSet< std::string > managedTypes;
    56         };
    5738
    5839        class ManagedTypes_new {
  • src/InitTweak/InitTweak.cc

    r0030b508 rfc12f05  
    2929#include "AST/Type.hpp"
    3030#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
    31 #include "Common/PassVisitor.h"
    3231#include "Common/SemanticError.h"  // for SemanticError
    3332#include "Common/UniqueName.h"     // for UniqueName
     
    3635#include "InitTweak.h"
    3736#include "ResolvExpr/Unify.h"      // for typesCompatibleIgnoreQualifiers
    38 #include "SymTab/Autogen.h"
    39 #include "SymTab/Indexer.h"        // for Indexer
    40 #include "SynTree/LinkageSpec.h"   // for Spec, isBuiltin, Intrinsic
    41 #include "SynTree/Attribute.h"     // for Attribute
    42 #include "SynTree/Constant.h"      // for Constant
    43 #include "SynTree/Declaration.h"   // for ObjectDecl, DeclarationWithType
    44 #include "SynTree/Expression.h"    // for Expression, UntypedExpr, Applicati...
    45 #include "SynTree/Initializer.h"   // for Initializer, ListInit, Designation
    46 #include "SynTree/Label.h"         // for Label
    47 #include "SynTree/Statement.h"     // for CompoundStmt, ExprStmt, BranchStmt
    48 #include "SynTree/Type.h"          // for FunctionType, ArrayType, PointerType
    49 #include "SynTree/Visitor.h"       // for Visitor, maybeAccept
    5037#include "Tuples/Tuples.h"         // for Tuples::isTtype
    5138
    5239namespace InitTweak {
    5340        namespace {
    54                 struct HasDesignations : public WithShortCircuiting {
    55                         bool hasDesignations = false;
    56 
    57                         void previsit( BaseSyntaxNode * ) {
    58                                 // short circuit if we already know there are designations
    59                                 if ( hasDesignations ) visit_children = false;
    60                         }
    61 
    62                         void previsit( Designation * des ) {
    63                                 // short circuit if we already know there are designations
    64                                 if ( hasDesignations ) visit_children = false;
    65                                 else if ( ! des->get_designators().empty() ) {
    66                                         hasDesignations = true;
    67                                         visit_children = false;
    68                                 }
    69                         }
    70                 };
    71 
    72                 struct InitDepthChecker : public WithGuards {
    73                         bool depthOkay = true;
    74                         Type * type;
    75                         int curDepth = 0, maxDepth = 0;
    76                         InitDepthChecker( Type * type ) : type( type ) {
    77                                 Type * t = type;
    78                                 while ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) {
    79                                         maxDepth++;
    80                                         t = at->get_base();
    81                                 }
    82                                 maxDepth++;
    83                         }
    84                         void previsit( ListInit * ) {
    85                                 curDepth++;
    86                                 GuardAction( [this]() { curDepth--; } );
    87                                 if ( curDepth > maxDepth ) depthOkay = false;
    88                         }
    89                 };
    90 
    9141                struct HasDesignations_new : public ast::WithShortCircuiting {
    9242                        bool result = false;
     
    10757                };
    10858
    109                 struct InitDepthChecker_new : public ast::WithGuards {
     59                struct InitDepthChecker_new {
    11060                        bool result = true;
    11161                        const ast::Type * type;
     
    11969                                maxDepth++;
    12070                        }
    121                         void previsit( ListInit * ) {
     71                        void previsit( ast::ListInit const * ) {
    12272                                curDepth++;
    123                                 GuardAction( [this]() { curDepth--; } );
    12473                                if ( curDepth > maxDepth ) result = false;
    12574                        }
    126                 };
    127 
    128                 struct InitFlattener_old : public WithShortCircuiting {
    129                         void previsit( SingleInit * singleInit ) {
    130                                 visit_children = false;
    131                                 argList.push_back( singleInit->value->clone() );
    132                         }
    133                         std::list< Expression * > argList;
     75                        void postvisit( ast::ListInit const * ) {
     76                                curDepth--;
     77                        }
    13478                };
    13579
     
    14488
    14589        } // anonymous namespace
    146 
    147         std::list< Expression * > makeInitList( Initializer * init ) {
    148                 PassVisitor<InitFlattener_old> flattener;
    149                 maybeAccept( init, flattener );
    150                 return flattener.pass.argList;
    151         }
    152 
    153         bool isDesignated( Initializer * init ) {
    154                 PassVisitor<HasDesignations> finder;
    155                 maybeAccept( init, finder );
    156                 return finder.pass.hasDesignations;
    157         }
    158 
    159         bool checkInitDepth( ObjectDecl * objDecl ) {
    160                 PassVisitor<InitDepthChecker> checker( objDecl->type );
    161                 maybeAccept( objDecl->init, checker );
    162                 return checker.pass.depthOkay;
    163         }
    16490
    16591        bool isDesignated( const ast::Init * init ) {
     
    180106        return std::move( flattener.core.argList );
    181107}
    182 
    183         class InitExpander_old::ExpanderImpl {
    184         public:
    185                 virtual ~ExpanderImpl() = default;
    186                 virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;
    187                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;
    188         };
    189 
    190         class InitImpl_old : public InitExpander_old::ExpanderImpl {
    191         public:
    192                 InitImpl_old( Initializer * init ) : init( init ) {}
    193                 virtual ~InitImpl_old() = default;
    194 
    195                 virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) {
    196                         // this is wrong, but just a placeholder for now
    197                         // if ( ! flattened ) flatten( indices );
    198                         // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();
    199                         return makeInitList( init );
    200                 }
    201 
    202                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
    203         private:
    204                 Initializer * init;
    205         };
    206 
    207         class ExprImpl_old : public InitExpander_old::ExpanderImpl {
    208         public:
    209                 ExprImpl_old( Expression * expr ) : arg( expr ) {}
    210                 virtual ~ExprImpl_old() { delete arg; }
    211 
    212                 virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
    213                         std::list< Expression * > ret;
    214                         Expression * expr = maybeClone( arg );
    215                         if ( expr ) {
    216                                 for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) {
    217                                         // go through indices and layer on subscript exprs ?[?]
    218                                         ++it;
    219                                         UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") );
    220                                         subscriptExpr->get_args().push_back( expr );
    221                                         subscriptExpr->get_args().push_back( (*it)->clone() );
    222                                         expr = subscriptExpr;
    223                                 }
    224                                 ret.push_back( expr );
    225                         }
    226                         return ret;
    227                 }
    228 
    229                 virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
    230         private:
    231                 Expression * arg;
    232         };
    233 
    234         InitExpander_old::InitExpander_old( Initializer * init ) : expander( new InitImpl_old( init ) ) {}
    235 
    236         InitExpander_old::InitExpander_old( Expression * expr ) : expander( new ExprImpl_old( expr ) ) {}
    237 
    238         std::list< Expression * > InitExpander_old::operator*() {
    239                 return cur;
    240         }
    241 
    242         InitExpander_old & InitExpander_old::operator++() {
    243                 cur = expander->next( indices );
    244                 return *this;
    245         }
    246 
    247         // use array indices list to build switch statement
    248         void InitExpander_old::addArrayIndex( Expression * index, Expression * dimension ) {
    249                 indices.push_back( index );
    250                 indices.push_back( dimension );
    251         }
    252 
    253         void InitExpander_old::clearArrayIndices() {
    254                 deleteAll( indices );
    255                 indices.clear();
    256         }
    257 
    258         bool InitExpander_old::addReference() {
    259                 bool added = false;
    260                 for ( Expression *& expr : cur ) {
    261                         expr = new AddressExpr( expr );
    262                         added = true;
    263                 }
    264                 return added;
    265         }
    266 
    267         namespace {
    268                 /// given index i, dimension d, initializer init, and callExpr f, generates
    269                 ///   if (i < d) f(..., init)
    270                 ///   ++i;
    271                 /// so that only elements within the range of the array are constructed
    272                 template< typename OutIterator >
    273                 void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {
    274                         UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );
    275                         cond->get_args().push_back( index->clone() );
    276                         cond->get_args().push_back( dimension->clone() );
    277 
    278                         std::list< Expression * > args = makeInitList( init );
    279                         callExpr->get_args().splice( callExpr->get_args().end(), args );
    280 
    281                         *out++ = new IfStmt( cond, new ExprStmt( callExpr ), nullptr );
    282 
    283                         UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );
    284                         increment->get_args().push_back( index->clone() );
    285                         *out++ = new ExprStmt( increment );
    286                 }
    287 
    288                 template< typename OutIterator >
    289                 void build( UntypedExpr * callExpr, InitExpander_old::IndexList::iterator idx, InitExpander_old::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
    290                         if ( idx == idxEnd ) return;
    291                         Expression * index = *idx++;
    292                         assert( idx != idxEnd );
    293                         Expression * dimension = *idx++;
    294 
    295                         // xxx - may want to eventually issue a warning here if we can detect
    296                         // that the number of elements exceeds to dimension of the array
    297                         if ( idx == idxEnd ) {
    298                                 if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {
    299                                         for ( Initializer * init : *listInit ) {
    300                                                 buildCallExpr( callExpr->clone(), index, dimension, init, out );
    301                                         }
    302                                 } else {
    303                                         buildCallExpr( callExpr->clone(), index, dimension, init, out );
    304                                 }
    305                         } else {
    306                                 std::list< Statement * > branches;
    307 
    308                                 unsigned long cond = 0;
    309                                 ListInit * listInit = dynamic_cast< ListInit * >( init );
    310                                 if ( ! listInit ) {
    311                                         // xxx - this shouldn't be an error, but need a way to
    312                                         // terminate without creating output, so should catch this error
    313                                         SemanticError( init->location, "unbalanced list initializers" );
    314                                 }
    315 
    316                                 static UniqueName targetLabel( "L__autogen__" );
    317                                 Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } );
    318                                 for ( Initializer * init : *listInit ) {
    319                                         Expression * condition;
    320                                         // check for designations
    321                                         // if ( init-> ) {
    322                                                 condition = new ConstantExpr( Constant::from_ulong( cond ) );
    323                                                 ++cond;
    324                                         // } else {
    325                                         //      condition = // ... take designation
    326                                         //      cond = // ... take designation+1
    327                                         // }
    328                                         std::list< Statement * > stmts;
    329                                         build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );
    330                                         stmts.push_back( new BranchStmt( switchLabel, BranchStmt::Break ) );
    331                                         CaseStmt * caseStmt = new CaseStmt( condition, stmts );
    332                                         branches.push_back( caseStmt );
    333                                 }
    334                                 *out++ = new SwitchStmt( index->clone(), branches );
    335                                 *out++ = new NullStmt( { switchLabel } );
    336                         }
    337                 }
    338         }
    339 
    340         // if array came with an initializer list: initialize each element
    341         // may have more initializers than elements in the array - need to check at each index that
    342         // we haven't exceeded size.
    343         // may have fewer initializers than elements in the array - need to default construct
    344         // remaining elements.
    345         // To accomplish this, generate switch statement, consuming all of expander's elements
    346         Statement * InitImpl_old::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
    347                 if ( ! init ) return nullptr;
    348                 CompoundStmt * block = new CompoundStmt();
    349                 build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) );
    350                 if ( block->get_kids().empty() ) {
    351                         delete block;
    352                         return nullptr;
    353                 } else {
    354                         init = nullptr; // init was consumed in creating the list init
    355                         return block;
    356                 }
    357         }
    358 
    359         Statement * ExprImpl_old::buildListInit( UntypedExpr *, std::list< Expression * > & ) {
    360                 return nullptr;
    361         }
    362 
    363         Statement * InitExpander_old::buildListInit( UntypedExpr * dst ) {
    364                 return expander->buildListInit( dst, indices );
    365         }
    366108
    367109class InitExpander_new::ExpanderImpl {
     
    535277}
    536278
    537         Type * getTypeofThis( FunctionType * ftype ) {
    538                 assertf( ftype, "getTypeofThis: nullptr ftype" );
    539                 ObjectDecl * thisParam = getParamThis( ftype );
    540                 ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type );
    541                 return refType->base;
    542         }
    543 
    544279        const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
    545280                assertf( ftype, "getTypeofThis: nullptr ftype" );
     
    552287        }
    553288
    554         ObjectDecl * getParamThis( FunctionType * ftype ) {
    555                 assertf( ftype, "getParamThis: nullptr ftype" );
    556                 auto & params = ftype->parameters;
    557                 assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() );
    558                 return strict_dynamic_cast< ObjectDecl * >( params.front() );
    559         }
    560 
    561289        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
    562290                assertf( func, "getParamThis: nullptr ftype" );
     
    564292                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
    565293                return params.front().strict_as<ast::ObjectDecl>();
    566         }
    567 
    568         bool tryConstruct( DeclarationWithType * dwt ) {
    569                 ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
    570                 if ( ! objDecl ) return false;
    571                 return (objDecl->get_init() == nullptr ||
    572                                 ( objDecl->get_init() != nullptr && objDecl->get_init()->get_maybeConstructed() ))
    573                         && ! objDecl->get_storageClasses().is_extern
    574                         && isConstructable( objDecl->type );
    575         }
    576 
    577         bool isConstructable( Type * type ) {
    578                 return ! dynamic_cast< VarArgsType * >( type ) && ! dynamic_cast< ReferenceType * >( type ) && ! dynamic_cast< FunctionType * >( type ) && ! Tuples::isTtype( type );
    579294        }
    580295
     
    593308        }
    594309
    595         struct CallFinder_old {
    596                 CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
    597 
    598                 void postvisit( ApplicationExpr * appExpr ) {
    599                         handleCallExpr( appExpr );
    600                 }
    601 
    602                 void postvisit( UntypedExpr * untypedExpr ) {
    603                         handleCallExpr( untypedExpr );
    604                 }
    605 
    606                 std::list< Expression * > * matches;
    607         private:
    608                 const std::list< std::string > names;
    609 
    610                 template< typename CallExpr >
    611                 void handleCallExpr( CallExpr * expr ) {
    612                         std::string fname = getFunctionName( expr );
    613                         if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
    614                                 matches->push_back( expr );
    615                         }
    616                 }
    617         };
    618 
    619310        struct CallFinder_new final {
    620311                std::vector< const ast::Expr * > matches;
     
    634325        };
    635326
    636         void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
    637                 static PassVisitor<CallFinder_old> finder( std::list< std::string >{ "?{}", "^?{}" } );
    638                 finder.pass.matches = &matches;
    639                 maybeAccept( stmt, finder );
    640         }
    641 
    642327        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    643328                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
     
    646331        }
    647332
    648         Expression * getCtorDtorCall( Statement * stmt ) {
    649                 std::list< Expression * > matches;
    650                 collectCtorDtorCalls( stmt, matches );
    651                 assertf( matches.size() <= 1, "%zd constructor/destructors found in %s", matches.size(), toString( stmt ).c_str() );
    652                 return matches.size() == 1 ? matches.front() : nullptr;
    653         }
    654 
    655333        namespace {
    656                 DeclarationWithType * getCalledFunction( Expression * expr );
    657 
    658                 template<typename CallExpr>
    659                 DeclarationWithType * handleDerefCalledFunction( CallExpr * expr ) {
    660                         // (*f)(x) => should get "f"
    661                         std::string name = getFunctionName( expr );
    662                         assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
    663                         assertf( ! expr->get_args().empty(), "Cannot get called function from dereference with no arguments" );
    664                         return getCalledFunction( expr->get_args().front() );
    665                 }
    666 
    667                 DeclarationWithType * getCalledFunction( Expression * expr ) {
    668                         assert( expr );
    669                         if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
    670                                 return varExpr->var;
    671                         } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( expr ) ) {
    672                                 return memberExpr->member;
    673                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    674                                 return getCalledFunction( castExpr->arg );
    675                         } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( expr ) ) {
    676                                 return handleDerefCalledFunction( untypedExpr );
    677                         } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {
    678                                 return handleDerefCalledFunction( appExpr );
    679                         } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
    680                                 return getCalledFunction( addrExpr->arg );
    681                         } else if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( expr ) ) {
    682                                 return getCalledFunction( commaExpr->arg2 );
    683                         }
    684                         return nullptr;
    685                 }
    686 
    687                 DeclarationWithType * getFunctionCore( const Expression * expr ) {
    688                         if ( const auto * appExpr = dynamic_cast< const ApplicationExpr * >( expr ) ) {
    689                                 return getCalledFunction( appExpr->function );
    690                         } else if ( const auto * untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {
    691                                 return getCalledFunction( untyped->function );
    692                         }
    693                         assertf( false, "getFunction with unknown expression: %s", toString( expr ).c_str() );
    694                 }
    695         }
    696 
    697         DeclarationWithType * getFunction( Expression * expr ) {
    698                 return getFunctionCore( expr );
    699         }
    700 
    701         const DeclarationWithType * getFunction( const Expression * expr ) {
    702                 return getFunctionCore( expr );
    703         }
    704 
    705         ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {
    706                 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );
    707                 if ( ! appExpr ) return nullptr;
    708                 DeclarationWithType * function = getCalledFunction( appExpr->get_function() );
    709                 assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() );
    710                 // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor
    711                 // will call all member dtors, and some members may have a user defined dtor.
    712                 return function->get_linkage() == LinkageSpec::Intrinsic ? appExpr : nullptr;
    713         }
    714 
    715         namespace {
    716                 template <typename Predicate>
    717                 bool allofCtorDtor( Statement * stmt, const Predicate & pred ) {
    718                         std::list< Expression * > callExprs;
    719                         collectCtorDtorCalls( stmt, callExprs );
    720                         return std::all_of( callExprs.begin(), callExprs.end(), pred);
    721                 }
    722 
    723334                template <typename Predicate>
    724335                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
     
    726337                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    727338                }
    728         }
    729 
    730         bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {
    731                 return allofCtorDtor( stmt, []( Expression * callExpr ){
    732                         if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
    733                                 FunctionType *funcType = GenPoly::getFunctionType( appExpr->function->result );
    734                                 assert( funcType );
    735                                 return funcType->get_parameters().size() == 1;
    736                         }
    737                         return false;
    738                 });
    739339        }
    740340
     
    749349                        return false;
    750350                });
    751         }
    752 
    753         bool isIntrinsicCallStmt( Statement * stmt ) {
    754                 return allofCtorDtor( stmt, []( Expression * callExpr ) {
    755                         return isIntrinsicCallExpr( callExpr );
    756                 });
    757         }
    758 
    759         namespace {
    760                 template<typename CallExpr>
    761                 Expression *& callArg( CallExpr * callExpr, unsigned int pos ) {
    762                         if ( pos >= callExpr->get_args().size() ) assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", pos, toString( callExpr ).c_str() );
    763                         for ( Expression *& arg : callExpr->get_args() ) {
    764                                 if ( pos == 0 ) return arg;
    765                                 pos--;
    766                         }
    767                         assert( false );
    768                 }
    769         }
    770 
    771         Expression *& getCallArg( Expression * callExpr, unsigned int pos ) {
    772                 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr ) ) {
    773                         return callArg( appExpr, pos );
    774                 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) {
    775                         return callArg( untypedExpr, pos );
    776                 } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) {
    777                         std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids();
    778                         assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." );
    779                         ExprStmt * stmt = strict_dynamic_cast< ExprStmt * >( stmts.back() );
    780                         TupleExpr * tuple = strict_dynamic_cast< TupleExpr * >( stmt->get_expr() );
    781                         assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." );
    782                         return getCallArg( tuple->get_exprs().front(), pos );
    783                 } else if ( ImplicitCopyCtorExpr * copyCtor = dynamic_cast< ImplicitCopyCtorExpr * >( callExpr ) ) {
    784                         return getCallArg( copyCtor->callExpr, pos );
    785                 } else {
    786                         assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );
    787                 }
    788         }
    789 
    790         namespace {
    791                 std::string funcName( Expression * func );
    792 
    793                 template<typename CallExpr>
    794                 std::string handleDerefName( CallExpr * expr ) {
    795                         // (*f)(x) => should get name "f"
    796                         std::string name = getFunctionName( expr );
    797                         assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
    798                         assertf( ! expr->get_args().empty(), "Cannot get function name from dereference with no arguments" );
    799                         return funcName( expr->get_args().front() );
    800                 }
    801 
    802                 std::string funcName( Expression * func ) {
    803                         if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( func ) ) {
    804                                 return nameExpr->get_name();
    805                         } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) {
    806                                 return varExpr->get_var()->get_name();
    807                         } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {
    808                                 return funcName( castExpr->get_arg() );
    809                         } else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) {
    810                                 return memberExpr->get_member()->get_name();
    811                         } else if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * > ( func ) ) {
    812                                 return funcName( memberExpr->get_member() );
    813                         } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( func ) ) {
    814                                 return handleDerefName( untypedExpr );
    815                         } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( func ) ) {
    816                                 return handleDerefName( appExpr );
    817                         } else if ( ConstructorExpr * ctorExpr = dynamic_cast< ConstructorExpr * >( func ) ) {
    818                                 return funcName( getCallArg( ctorExpr->get_callExpr(), 0 ) );
    819                         } else {
    820                                 assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );
    821                         }
    822                 }
    823         }
    824 
    825         std::string getFunctionName( Expression * expr ) {
    826                 // there's some unforunate overlap here with getCalledFunction. Ideally this would be able to use getCalledFunction and
    827                 // return the name of the DeclarationWithType, but this needs to work for NameExpr and UntypedMemberExpr, where getCalledFunction
    828                 // can't possibly do anything reasonable.
    829                 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr ) ) {
    830                         return funcName( appExpr->get_function() );
    831                 } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * > ( expr ) ) {
    832                         return funcName( untypedExpr->get_function() );
    833                 } else {
    834                         std::cerr << expr << std::endl;
    835                         assertf( false, "Unexpected expression type passed to getFunctionName" );
    836                 }
    837         }
    838 
    839         Type * getPointerBase( Type * type ) {
    840                 if ( PointerType * ptrType = dynamic_cast< PointerType * >( type ) ) {
    841                         return ptrType->get_base();
    842                 } else if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    843                         return arrayType->get_base();
    844                 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) {
    845                         return refType->get_base();
    846                 } else {
    847                         return nullptr;
    848                 }
    849         }
    850 
    851         Type * isPointerType( Type * type ) {
    852                 return getPointerBase( type ) ? type : nullptr;
    853         }
    854 
    855         ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src ) {
    856                 static FunctionDecl * assign = nullptr;
    857                 if ( ! assign ) {
    858                         // temporary? Generate a fake assignment operator to represent bitwise assignments.
    859                         // This operator could easily exist as a real function, but it's tricky because nothing should resolve to this function.
    860                         TypeDecl * td = new TypeDecl( "T", noStorageClasses, nullptr, TypeDecl::Dtype, true );
    861                         assign = new FunctionDecl( "?=?", noStorageClasses, LinkageSpec::Intrinsic, SymTab::genAssignType( new TypeInstType( noQualifiers, td->name, td ) ), nullptr );
    862                 }
    863                 if ( dynamic_cast< ReferenceType * >( dst->result ) ) {
    864                         for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
    865                                 dst = new AddressExpr( dst );
    866                         }
    867                 } else {
    868                         dst = new CastExpr( dst, new ReferenceType( noQualifiers, dst->result->clone() ) );
    869                 }
    870                 if ( dynamic_cast< ReferenceType * >( src->result ) ) {
    871                         for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
    872                                 src = new AddressExpr( src );
    873                         }
    874                 }
    875                 return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );
    876351        }
    877352
     
    905380                return app;
    906381        }
    907 
    908         struct ConstExprChecker : public WithShortCircuiting {
    909                 // most expressions are not const expr
    910                 void previsit( Expression * ) { isConstExpr = false; visit_children = false; }
    911 
    912                 void previsit( AddressExpr *addressExpr ) {
    913                         visit_children = false;
    914 
    915                         // address of a variable or member expression is constexpr
    916                         Expression * arg = addressExpr->get_arg();
    917                         if ( ! dynamic_cast< NameExpr * >( arg) && ! dynamic_cast< VariableExpr * >( arg ) && ! dynamic_cast< MemberExpr * >( arg ) && ! dynamic_cast< UntypedMemberExpr * >( arg ) ) isConstExpr = false;
    918                 }
    919 
    920                 // these expressions may be const expr, depending on their children
    921                 void previsit( SizeofExpr * ) {}
    922                 void previsit( AlignofExpr * ) {}
    923                 void previsit( UntypedOffsetofExpr * ) {}
    924                 void previsit( OffsetofExpr * ) {}
    925                 void previsit( OffsetPackExpr * ) {}
    926                 void previsit( CommaExpr * ) {}
    927                 void previsit( LogicalExpr * ) {}
    928                 void previsit( ConditionalExpr * ) {}
    929                 void previsit( CastExpr * ) {}
    930                 void previsit( ConstantExpr * ) {}
    931 
    932                 void previsit( VariableExpr * varExpr ) {
    933                         visit_children = false;
    934 
    935                         if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( varExpr->result ) ) {
    936                                 long long int value;
    937                                 if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
    938                                         // enumerators are const expr
    939                                         return;
    940                                 }
    941                         }
    942                         isConstExpr = false;
    943                 }
    944 
    945                 bool isConstExpr = true;
    946         };
    947382
    948383        struct ConstExprChecker_new : public ast::WithShortCircuiting {
     
    989424        };
    990425
    991         bool isConstExpr( Expression * expr ) {
    992                 if ( expr ) {
    993                         PassVisitor<ConstExprChecker> checker;
    994                         expr->accept( checker );
    995                         return checker.pass.isConstExpr;
    996                 }
    997                 return true;
    998         }
    999 
    1000         bool isConstExpr( Initializer * init ) {
    1001                 if ( init ) {
    1002                         PassVisitor<ConstExprChecker> checker;
    1003                         init->accept( checker );
    1004                         return checker.pass.isConstExpr;
    1005                 } // if
    1006                 // for all intents and purposes, no initializer means const expr
    1007                 return true;
    1008         }
    1009 
    1010426        bool isConstExpr( const ast::Expr * expr ) {
    1011427                if ( expr ) {
     
    1027443        }
    1028444
    1029         const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ) {
    1030                 const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( decl );
    1031                 if ( ! function ) return nullptr;
    1032                 if ( function->name != fname ) return nullptr;
    1033                 FunctionType * ftype = function->type;
    1034                 if ( ftype->parameters.size() != 2 ) return nullptr;
    1035 
    1036                 Type * t1 = getPointerBase( ftype->get_parameters().front()->get_type() );
    1037                 Type * t2 = ftype->parameters.back()->get_type();
    1038                 assert( t1 );
    1039 
    1040                 if ( ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, SymTab::Indexer() ) ) {
    1041                         return function;
    1042                 } else {
    1043                         return nullptr;
    1044                 }
    1045         }
    1046 
    1047445bool isAssignment( const ast::FunctionDecl * decl ) {
    1048446        return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
     
    1071469        return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
    1072470}
    1073 
    1074 
    1075         const FunctionDecl * isAssignment( const Declaration * decl ) {
    1076                 return isCopyFunction( decl, "?=?" );
    1077         }
    1078         const FunctionDecl * isDestructor( const Declaration * decl ) {
    1079                 if ( CodeGen::isDestructor( decl->name ) ) {
    1080                         return dynamic_cast< const FunctionDecl * >( decl );
    1081                 }
    1082                 return nullptr;
    1083         }
    1084         const FunctionDecl * isDefaultConstructor( const Declaration * decl ) {
    1085                 if ( CodeGen::isConstructor( decl->name ) ) {
    1086                         if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) {
    1087                                 if ( func->type->parameters.size() == 1 ) {
    1088                                         return func;
    1089                                 }
    1090                         }
    1091                 }
    1092                 return nullptr;
    1093         }
    1094         const FunctionDecl * isCopyConstructor( const Declaration * decl ) {
    1095                 return isCopyFunction( decl, "?{}" );
    1096         }
    1097471
    1098472        #if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
     
    1103477        static const char * const data_section =  ".data" ASM_COMMENT;
    1104478        static const char * const tlsd_section = ".tdata" ASM_COMMENT;
    1105         void addDataSectionAttribute( ObjectDecl * objDecl ) {
    1106                 const bool is_tls = objDecl->get_storageClasses().is_threadlocal_any();
    1107                 const char * section = is_tls ? tlsd_section : data_section;
    1108                 objDecl->attributes.push_back(new Attribute("section", {
    1109                         new ConstantExpr( Constant::from_string( section ) )
    1110                 }));
    1111         }
    1112479
    1113480        void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
  • src/InitTweak/InitTweak.h

    r0030b508 rfc12f05  
    2222
    2323#include "AST/Fwd.hpp"        // for AST nodes
    24 #include "SynTree/SynTree.h"  // for Visitor Nodes
    2524
    2625// helper functions for initialization
    2726namespace InitTweak {
    28         const FunctionDecl * isAssignment( const Declaration * decl );
    29         const FunctionDecl * isDestructor( const Declaration * decl );
    30         const FunctionDecl * isDefaultConstructor( const Declaration * decl );
    31         const FunctionDecl * isCopyConstructor( const Declaration * decl );
    32         const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname );
    3327        bool isAssignment( const ast::FunctionDecl * decl );
    3428        bool isDestructor( const ast::FunctionDecl * decl );
     
    3832
    3933        /// returns the base type of the first parameter to a constructor/destructor/assignment function
    40         Type * getTypeofThis( FunctionType * ftype );
    4134        const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
    4235
    4336        /// returns the first parameter of a constructor/destructor/assignment function
    44         ObjectDecl * getParamThis( FunctionType * ftype );
    4537        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    4638
    4739        /// generate a bitwise assignment operation.
    48         ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
    49 
    5040        ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    5141
    5242        /// transform Initializer into an argument list that can be passed to a call expression
    53         std::list< Expression * > makeInitList( Initializer * init );
    5443        std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
    5544
    5645        /// True if the resolver should try to construct dwt
    57         bool tryConstruct( DeclarationWithType * dwt );
    5846        bool tryConstruct( const ast::DeclWithType * dwt );
    5947
    6048        /// True if the type can have a user-defined constructor
    61         bool isConstructable( Type * t );
    6249        bool isConstructable( const ast::Type * t );
    6350
    6451        /// True if the Initializer contains designations
    65         bool isDesignated( Initializer * init );
    6652        bool isDesignated( const ast::Init * init );
    6753
    6854        /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
    6955        /// type, where the depth of its type is the number of nested ArrayTypes + 1
    70         bool checkInitDepth( ObjectDecl * objDecl );
    7156        bool checkInitDepth( const ast::ObjectDecl * objDecl );
    72 
    73         /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)
    74         DeclarationWithType * getFunction( Expression * expr );
    75         const DeclarationWithType * getFunction( const Expression * expr );
    76 
    77         /// Non-Null if expr is a call expression whose target function is intrinsic
    78         ApplicationExpr * isIntrinsicCallExpr( Expression * expr );
    7957
    8058        /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
    8159        /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
    8260        /// Currently has assertions that make it less than fully general.
    83         bool isIntrinsicSingleArgCallStmt( Statement * stmt );
    8461        bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
    8562
    86         /// True if stmt is a call statement where the function called is intrinsic.
    87         bool isIntrinsicCallStmt( Statement * stmt );
    88 
    8963        /// get all Ctor/Dtor call expressions from a Statement
    90         void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    9164        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
    9265
    93         /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
    94         Expression * getCtorDtorCall( Statement * stmt );
    95 
    96         /// returns the name of the function being called
    97         std::string getFunctionName( Expression * expr );
    98 
    99         /// returns the argument to a call expression in position N indexed from 0
    100         Expression *& getCallArg( Expression * callExpr, unsigned int pos );
    101 
    102         /// returns the base type of a PointerType or ArrayType, else returns NULL
    103         Type * getPointerBase( Type * );
    104 
    105         /// returns the argument if it is a PointerType or ArrayType, else returns NULL
    106         Type * isPointerType( Type * );
    107 
    10866        /// returns true if expr is trivially a compile-time constant
    109         bool isConstExpr( Expression * expr );
    110         bool isConstExpr( Initializer * init );
    111 
    11267        bool isConstExpr( const ast::Expr * expr );
    11368        bool isConstExpr( const ast::Init * init );
     
    12277        ///    .section .data#,"a"
    12378        /// to avoid assembler warning "ignoring changed section attributes for .data"
    124         void addDataSectionAttribute( ObjectDecl * objDecl );
    125 
    12679        void addDataSectionAttribute( ast::ObjectDecl * objDecl );
    127 
    128         class InitExpander_old {
    129         public:
    130                 // expand by stepping through init to get each list of arguments
    131                 InitExpander_old( Initializer * init );
    132 
    133                 // always expand to expr
    134                 InitExpander_old( Expression * expr );
    135 
    136                 // iterator-like interface
    137                 std::list< Expression * > operator*();
    138                 InitExpander_old & operator++();
    139 
    140                 // builds statement which has the same semantics as a C-style list initializer
    141                 // (for array initializers) using callExpr as the base expression to perform initialization
    142                 Statement * buildListInit( UntypedExpr * callExpr );
    143                 void addArrayIndex( Expression * index, Expression * dimension );
    144                 void clearArrayIndices();
    145                 bool addReference();
    146 
    147                 class ExpanderImpl;
    148 
    149                 typedef std::list< Expression * > IndexList;
    150         private:
    151                 std::shared_ptr< ExpanderImpl > expander;
    152                 std::list< Expression * > cur;
    153 
    154                 // invariant: list of size 2N (elements come in pairs [index, dimension])
    155                 IndexList indices;
    156         };
    15780
    15881        class InitExpander_new {
  • src/InitTweak/module.mk

    r0030b508 rfc12f05  
    2424        InitTweak/FixGlobalInit.cc \
    2525        InitTweak/FixGlobalInit.h \
    26         InitTweak/FixInit.cc \
    2726        InitTweak/FixInit.h \
    2827        InitTweak/FixInitNew.cpp
  • src/MakeLibCfa.h

    r0030b508 rfc12f05  
    2424
    2525namespace LibCfa {
    26         void makeLibCfa( std::list< Declaration* > &prelude );
    2726        void makeLibCfa( ast::TranslationUnit & translationUnit );
    2827} // namespace LibCfa
  • src/Makefile.am

    r0030b508 rfc12f05  
    2222      CompilationState.cc \
    2323      CompilationState.h \
    24       MakeLibCfa.cc \
    2524          MakeLibCfaNew.cpp \
    2625        MakeLibCfa.h
     
    4241include AST/module.mk
    4342include CodeGen/module.mk
    44 include CodeTools/module.mk
    4543include Concurrency/module.mk
    4644include Common/module.mk
     
    5149include ResolvExpr/module.mk
    5250include SymTab/module.mk
    53 include SynTree/module.mk
    5451include Tuples/module.mk
    5552include Validate/module.mk
    5653include Virtual/module.mk
    5754
    58 $(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/SynTree/Type.h
     55$(addprefix $(srcdir)/, ResolvExpr/ConversionCost.cc ResolvExpr/CommonType.cc SymTab/ManglerCommon.cc) : $(srcdir)/AST/Type.hpp
    5956
    6057$(srcdir)/AST/Type.hpp : BasicTypes-gen.cc
  • src/Parser/RunParser.cpp

    r0030b508 rfc12f05  
    1616#include "RunParser.hpp"
    1717
    18 #include "AST/Convert.hpp"                  // for convert
    1918#include "AST/TranslationUnit.hpp"          // for TranslationUnit
    20 #include "CodeTools/TrackLoc.h"             // for fillLocations
    2119#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    2220#include "Parser/DeclarationNode.h"         // for DeclarationNode, buildList
  • src/Parser/StatementNode.cc

    r0030b508 rfc12f05  
    503503} // build_corun
    504504
     505ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ) {
     506        std::vector<ast::ptr<ast::Stmt>> astinit;                                               // maybe empty
     507        buildMoveList( forctl->init, astinit );
     508
     509        ast::Expr * astcond = nullptr;                                          // maybe empty
     510        astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
     511
     512        ast::Expr * astincr = nullptr;                                          // maybe empty
     513        astincr = maybeMoveBuild( forctl->change );
     514        delete forctl;
     515
     516        return new ast::CoforStmt( location,
     517                std::move( astinit ),
     518                astcond,
     519                astincr,
     520                buildMoveSingle( stmt )
     521        );
     522} // build_cofor
     523
    505524// Local Variables: //
    506525// tab-width: 4 //
  • src/Parser/StatementNode.h

    r0030b508 rfc12f05  
    106106ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
    107107ast::Stmt * build_corun( const CodeLocation &, StatementNode * stmt );
     108ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt );
  • src/Parser/parser.yy

    r0030b508 rfc12f05  
    4848using namespace std;
    4949
    50 #include "SynTree/Type.h"                               // for Type
    5150#include "DeclarationNode.h"                            // for DeclarationNode, ...
    5251#include "ExpressionNode.h"                             // for ExpressionNode, ...
     
    5857#include "Common/SemanticError.h"                                               // error_str
    5958#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
    60 
    61 #include "SynTree/Attribute.h"                                                  // for Attribute
    6259
    6360// lex uses __null in a boolean context, it's fine.
     
    17261723cofor_statement:
    17271724        COFOR '(' for_control_expression_list ')' statement
    1728                 { SemanticError( yylloc, "cofor statement is currently unimplemented." ); $$ = nullptr; }
     1725                { $$ = new StatementNode( build_cofor( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
    17291726        ;
    17301727
     
    21692166type_qualifier_name:
    21702167        CONST
    2171                 { $$ = DeclarationNode::newTypeQualifier( Type::Const ); }
     2168                { $$ = DeclarationNode::newTypeQualifier( ast::CV::Const ); }
    21722169        | RESTRICT
    2173                 { $$ = DeclarationNode::newTypeQualifier( Type::Restrict ); }
     2170                { $$ = DeclarationNode::newTypeQualifier( ast::CV::Restrict ); }
    21742171        | VOLATILE
    2175                 { $$ = DeclarationNode::newTypeQualifier( Type::Volatile ); }
     2172                { $$ = DeclarationNode::newTypeQualifier( ast::CV::Volatile ); }
    21762173        | ATOMIC
    2177                 { $$ = DeclarationNode::newTypeQualifier( Type::Atomic ); }
     2174                { $$ = DeclarationNode::newTypeQualifier( ast::CV::Atomic ); }
    21782175        | forall
    21792176                { $$ = DeclarationNode::newForall( $1 ); }
     
    22062203storage_class:
    22072204        EXTERN
    2208                 { $$ = DeclarationNode::newStorageClass( Type::Extern ); }
     2205                { $$ = DeclarationNode::newStorageClass( ast::Storage::Extern ); }
    22092206        | STATIC
    2210                 { $$ = DeclarationNode::newStorageClass( Type::Static ); }
     2207                { $$ = DeclarationNode::newStorageClass( ast::Storage::Static ); }
    22112208        | AUTO
    2212                 { $$ = DeclarationNode::newStorageClass( Type::Auto ); }
     2209                { $$ = DeclarationNode::newStorageClass( ast::Storage::Auto ); }
    22132210        | REGISTER
    2214                 { $$ = DeclarationNode::newStorageClass( Type::Register ); }
     2211                { $$ = DeclarationNode::newStorageClass( ast::Storage::Register ); }
    22152212        | THREADLOCALGCC                                                                                // GCC
    2216                 { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalGcc ); }
     2213                { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalGcc ); }
    22172214        | THREADLOCALC11                                                                                // C11
    2218                 { $$ = DeclarationNode::newStorageClass( Type::ThreadlocalC11 ); }
     2215                { $$ = DeclarationNode::newStorageClass( ast::Storage::ThreadLocalC11 ); }
    22192216                // Put function specifiers here to simplify parsing rules, but separate them semantically.
    22202217        | INLINE                                                                                        // C99
    2221                 { $$ = DeclarationNode::newFuncSpecifier( Type::Inline ); }
     2218                { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Inline ); }
    22222219        | FORTRAN                                                                                       // C99
    2223                 { $$ = DeclarationNode::newFuncSpecifier( Type::Fortran ); }
     2220                { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Fortran ); }
    22242221        | NORETURN                                                                                      // C11
    2225                 { $$ = DeclarationNode::newFuncSpecifier( Type::Noreturn ); }
     2222                { $$ = DeclarationNode::newFuncSpecifier( ast::Function::Noreturn ); }
    22262223        ;
    22272224
     
    37173714                { $$ = $1->addQualifiers( $2 ); }
    37183715        | '&' MUTEX paren_identifier attribute_list_opt
    3719                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3716                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37203717        | identifier_parameter_ptr
    37213718        | identifier_parameter_array attribute_list_opt
     
    37673764                { $$ = $1->addQualifiers( $2 ); }
    37683765        | '&' MUTEX typedef_name attribute_list_opt
    3769                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3766                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37703767        | type_parameter_ptr
    37713768        | type_parameter_array attribute_list_opt
     
    39413938        abstract_parameter_ptr
    39423939        | '&' MUTEX attribute_list_opt
    3943                 { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }
     3940                { $$ = DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf )->addQualifiers( $3 ); }
    39443941        | abstract_parameter_array attribute_list_opt
    39453942                { $$ = $1->addQualifiers( $2 ); }
  • src/ResolvExpr/AdjustExprType.cc

    r0030b508 rfc12f05  
    1919#include "AST/Type.hpp"
    2020#include "AST/TypeEnvironment.hpp"
    21 #include "Common/PassVisitor.h"
    22 #include "SymTab/Indexer.h"       // for Indexer
    23 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Kind::Ftype
    24 #include "SynTree/Mutator.h"      // for Mutator
    25 #include "SynTree/Type.h"         // for PointerType, TypeInstType, Type
    26 #include "TypeEnvironment.h"      // for EqvClass, TypeEnvironment
    2721
    2822namespace ResolvExpr {
    29 
    30 namespace {
    31         class AdjustExprType_old final : public WithShortCircuiting {
    32                 public:
    33                 AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer );
    34                 void premutate( VoidType * ) { visit_children = false; }
    35                 void premutate( BasicType * ) { visit_children = false; }
    36                 void premutate( PointerType * ) { visit_children = false; }
    37                 void premutate( ArrayType * ) { visit_children = false; }
    38                 void premutate( FunctionType * ) { visit_children = false; }
    39                 void premutate( StructInstType * ) { visit_children = false; }
    40                 void premutate( UnionInstType * ) { visit_children = false; }
    41                 void premutate( EnumInstType * ) { visit_children = false; }
    42                 void premutate( TraitInstType * ) { visit_children = false; }
    43                 void premutate( TypeInstType * ) { visit_children = false; }
    44                 void premutate( TupleType * ) { visit_children = false; }
    45                 void premutate( VarArgsType * ) { visit_children = false; }
    46                 void premutate( ZeroType * ) { visit_children = false; }
    47                 void premutate( OneType * ) { visit_children = false; }
    48 
    49                 Type * postmutate( ArrayType * arrayType );
    50                 Type * postmutate( FunctionType * functionType );
    51                 Type * postmutate( TypeInstType * aggregateUseType );
    52 
    53                 private:
    54                 const TypeEnvironment & env;
    55                 const SymTab::Indexer & indexer;
    56         };
    57 
    58         AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer )
    59                 : env( env ), indexer( indexer ) {
    60         }
    61 
    62         Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) {
    63                 PointerType * pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };
    64                 arrayType->base = nullptr;
    65                 delete arrayType;
    66                 return pointerType;
    67         }
    68 
    69         Type * AdjustExprType_old::postmutate( FunctionType * functionType ) {
    70                 return new PointerType{ Type::Qualifiers(), functionType };
    71         }
    72 
    73         Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) {
    74                 if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {
    75                         if ( eqvClass->data.kind == TypeDecl::Ftype ) {
    76                                 return new PointerType{ Type::Qualifiers(), typeInst };
    77                         }
    78                 } else if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->get_name() ) ) {
    79                         if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl * >( ntDecl ) ) {
    80                                 if ( tyDecl->get_kind() == TypeDecl::Ftype ) {
    81                                         return new PointerType{ Type::Qualifiers(), typeInst };
    82                                 } // if
    83                         } // if
    84                 } // if
    85                 return typeInst;
    86         }
    87 } // anonymous namespace
    88 
    89 void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    90         PassVisitor<AdjustExprType_old> adjuster( env, indexer );
    91         Type * newType = type->acceptMutator( adjuster );
    92         type = newType;
    93 }
    94 
    95 void adjustExprType( Type *& type ) {
    96         TypeEnvironment env;
    97         SymTab::Indexer indexer;
    98         adjustExprType( type, env, indexer );
    99 }
    10023
    10124namespace {
  • src/ResolvExpr/CandidateFinder.cpp

    r0030b508 rfc12f05  
    5757
    5858/// Unique identifier for matching expression resolutions to their requesting expression
    59 UniqueId globalResnSlot = 0;
     59ast::UniqueId globalResnSlot = 0;
    6060
    6161namespace {
     
    686686        void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) {
    687687                // Set need bindings for any unbound assertions
    688                 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
     688                ast::UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
    689689                for ( auto & assn : newCand->need ) {
    690690                        // skip already-matched assertions
  • src/ResolvExpr/CastCost.cc

    r0030b508 rfc12f05  
    2626#include "ResolvExpr/ConversionCost.h"   // for conversionCost
    2727#include "ResolvExpr/PtrsCastable.hpp"   // for ptrsCastable
    28 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment, EqvClass
    2928#include "ResolvExpr/typeops.h"          // for ptrsCastable
    3029#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    31 #include "SymTab/Indexer.h"              // for Indexer
    32 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    33 #include "SynTree/Type.h"                // for PointerType, Type, TypeInstType
    3430
    3531#if 0
     
    4036
    4137namespace ResolvExpr {
    42         struct CastCost_old : public ConversionCost {
    43           public:
    44                 CastCost_old( const Type * dest, bool srcIsLvalue,
    45                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );
    46 
    47                 using ConversionCost::previsit;
    48                 using ConversionCost::postvisit;
    49                 void postvisit( const BasicType * basicType );
    50                 void postvisit( const PointerType * pointerType );
    51         };
    52 
    53         Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,
    54                         const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    55                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    56                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
    57                                 if ( eqvClass->type ) {
    58                                         return castCost( src, eqvClass->type, srcIsLvalue, indexer, env );
    59                                 } else {
    60                                         return Cost::infinity;
    61                                 }
    62                         } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
    63                                 // all typedefs should be gone by this point
    64                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType );
    65                                 if ( type->base ) {
    66                                         return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe;
    67                                 } // if
    68                         } // if
    69                 } // if
    70 
    71                 PRINT(
    72                         std::cerr << "castCost ::: src is ";
    73                         src->print( std::cerr );
    74                         std::cerr << std::endl << "dest is ";
    75                         dest->print( std::cerr );
    76                         std::cerr << std::endl << "env is" << std::endl;
    77                         env.print( std::cerr, 8 );
    78                 )
    79 
    80                 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    81                         PRINT( std::cerr << "compatible!" << std::endl; )
    82                         return Cost::zero;
    83                 } else if ( dynamic_cast< const VoidType * >( dest ) ) {
    84                         return Cost::safe;
    85                 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
    86                         PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    87                         return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    88                                 return ptrsCastable( t1, t2, env, indexer );
    89                         });
    90                 } else {
    91                         PassVisitor<CastCost_old> converter(
    92                                 dest, srcIsLvalue, indexer, env,
    93                                 (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & ))
    94                                         castCost );
    95                         src->accept( converter );
    96                         if ( converter.pass.get_cost() == Cost::infinity ) {
    97                                 return Cost::infinity;
    98                         } else {
    99                                 // xxx - why are we adding cost 0 here?
    100                                 return converter.pass.get_cost() + Cost::zero;
    101                         } // if
    102                 } // if
    103         }
    104 
    105         CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue,
    106                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
    107                 : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) {
    108         }
    109 
    110         void CastCost_old::postvisit( const BasicType * basicType ) {
    111                 const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest );
    112                 if ( destAsPointer && basicType->isInteger() ) {
    113                         // necessary for, e.g. unsigned long => void *
    114                         cost = Cost::unsafe;
    115                 } else {
    116                         cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env );
    117                 } // if
    118         }
    119 
    120         void CastCost_old::postvisit( const PointerType * pointerType ) {
    121                 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
    122                         if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
    123                                 cost = Cost::safe;
    124                         } else {
    125                                 TypeEnvironment newEnv( env );
    126                                 newEnv.add( pointerType->forall );
    127                                 newEnv.add( pointerType->base->forall );
    128                                 int castResult = ptrsCastable( pointerType->base, destAsPtr->base, newEnv, indexer );
    129                                 if ( castResult > 0 ) {
    130                                         cost = Cost::safe;
    131                                 } else if ( castResult < 0 ) {
    132                                         cost = Cost::infinity;
    133                                 } // if
    134                         } // if
    135                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    136                         if ( destAsBasic->isInteger() ) {
    137                                 // necessary for, e.g. void * => unsigned long
    138                                 cost = Cost::unsafe;
    139                         } // if
    140                 }
    141         }
    14238
    14339namespace {
     
    20096} // anonymous namespace
    20197
    202 
    203 
    20498Cost castCost(
    20599        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
  • src/ResolvExpr/CommonType.cc

    r0030b508 rfc12f05  
    2323#include "AST/Pass.hpp"
    2424#include "AST/Type.hpp"
    25 #include "Common/PassVisitor.h"
    26 #include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
    27 #include "SymTab/Indexer.h"              // for Indexer
    28 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl (ptr...
    29 #include "SynTree/Type.h"                // for BasicType, BasicType::Kind::...
    30 #include "SynTree/Visitor.h"             // for Visitor
    3125#include "Unify.h"                       // for unifyExact, WidenMode
    3226#include "typeops.h"                     // for isFtype
     
    4135
    4236namespace ResolvExpr {
    43         struct CommonType_old : public WithShortCircuiting {
    44                 CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
    45                 Type * get_result() const { return result; }
    46 
    47                 void previsit( BaseSyntaxNode * ) { visit_children = false; }
    48 
    49                 void postvisit( VoidType * voidType );
    50                 void postvisit( BasicType * basicType );
    51                 void postvisit( PointerType * pointerType );
    52                 void postvisit( ArrayType * arrayType );
    53                 void postvisit( ReferenceType * refType );
    54                 void postvisit( FunctionType * functionType );
    55                 void postvisit( StructInstType * aggregateUseType );
    56                 void postvisit( UnionInstType * aggregateUseType );
    57                 void postvisit( EnumInstType * aggregateUseType );
    58                 void postvisit( TraitInstType * aggregateUseType );
    59                 void postvisit( TypeInstType * aggregateUseType );
    60                 void postvisit( TupleType * tupleType );
    61                 void postvisit( VarArgsType * varArgsType );
    62                 void postvisit( ZeroType * zeroType );
    63                 void postvisit( OneType * oneType );
    64 
    65           private:
    66                 template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer );
    67                 template< typename RefType > void handleRefType( RefType * inst, Type * other );
    68 
    69                 Type * result;
    70                 Type * type2;                           // inherited
    71                 bool widenFirst, widenSecond;
    72                 const SymTab::Indexer &indexer;
    73                 TypeEnvironment &env;
    74                 const OpenVarSet &openVars;
    75         };
    76 
    77         Type * handleReference( Type * t1, Type * t2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {
    78                 Type * common = nullptr;
    79                 AssertionSet have, need;
    80                 OpenVarSet newOpen( openVars );
    81                 // need unify to bind type variables
    82                 if ( unify( t1, t2, env, have, need, newOpen, indexer, common ) ) {
    83                         PRINT(
    84                                 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
    85                         )
    86                         if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) {
    87                                 PRINT(
    88                                         std::cerr << "widen okay" << std::endl;
    89                                 )
    90                                 common->tq |= t1->tq;
    91                                 common->tq |= t2->tq;
    92                                 return common;
    93                         }
    94                 }
    95                 PRINT(
    96                         std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
    97                 )
    98                 return nullptr;
    99         }
    100 
    101         Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
    102                 PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
    103 
    104                 int depth1 = type1->referenceDepth();
    105                 int depth2 = type2->referenceDepth();
    106                 if ( depth1 > 0 || depth2 > 0 ) {
    107                         int diff = depth1-depth2;
    108                         // TODO: should it be possible for commonType to generate complicated conversions? I would argue no, only conversions that involve types of the same reference level or a difference of 1 should be allowed.
    109                         // if ( diff > 1 || diff < -1 ) return nullptr;
    110 
    111                         // special case where one type has a reference depth of 1 larger than the other
    112                         if ( diff > 0 || diff < 0 ) {
    113                                 PRINT(
    114                                         std::cerr << "reference depth diff: " << diff << std::endl;
    115                                 )
    116                                 Type * result = nullptr;
    117                                 ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 );
    118                                 ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 );
    119                                 if ( diff > 0 ) {
    120                                         // deeper on the left
    121                                         assert( ref1 );
    122                                         result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );
    123                                 } else {
    124                                         // deeper on the right
    125                                         assert( ref2 );
    126                                         result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );
    127                                 }
    128                                 if ( result && ref1 ) {
    129                                         // formal is reference, so result should be reference
    130                                         PRINT(
    131                                                 std::cerr << "formal is reference; result should be reference" << std::endl;
    132                                         )
    133                                         result = new ReferenceType( ref1->tq, result );
    134                                 }
    135                                 PRINT(
    136                                         std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl;
    137                                 )
    138                                 return result;
    139                         }
    140                         // otherwise, both are reference types of the same depth and this is handled by the CommonType visitor.
    141                 }
    142 
    143                 type1->accept( visitor );
    144                 Type * result = visitor.pass.get_result();
    145                 if ( ! result ) {
    146                         // this appears to be handling for opaque type declarations
    147                         if ( widenSecond ) {
    148                                 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) {
    149                                         if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) {
    150                                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );
    151                                                 if ( type->get_base() ) {
    152                                                         Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq;
    153                                                         AssertionSet have, need;
    154                                                         OpenVarSet newOpen( openVars );
    155                                                         type1->tq = Type::Qualifiers();
    156                                                         type->get_base()->tq = tq1;
    157                                                         if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) {
    158                                                                 result = type1->clone();
    159                                                                 result->tq = tq1 | tq2;
    160                                                         } // if
    161                                                         type1->tq = tq1;
    162                                                         type->get_base()->tq = Type::Qualifiers();
    163                                                 } // if
    164                                         } // if
    165                                 } // if
    166                         } // if
    167                 } // if
    168 #ifdef DEBUG
    169                 std::cerr << "============= commonType" << std::endl << "type1 is ";
    170                 type1->print( std::cerr );
    171                 std::cerr << " type2 is ";
    172                 type2->print( std::cerr );
    173                 if ( result ) {
    174                         std::cerr << " common type is ";
    175                         result->print( std::cerr );
    176                 } else {
    177                         std::cerr << " no common type";
    178                 } // if
    179                 std::cerr << std::endl;
    180 #endif
    181                 return result;
    182         }
    18337
    18438        // GENERATED START, DO NOT EDIT
    18539        // GENERATED BY BasicTypes-gen.cc
    186         #define BT BasicType::
    187         static const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
     40        #define BT ast::BasicType::
     41        static const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
    18842                /*                                      B                       C                      SC                      UC                      SI                     SUI
    18943                                                        I                      UI                      LI                     LUI                     LLI                    LLUI
     
    485339        // GENERATED END
    486340        static_assert(
    487                 sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
     341                sizeof(commonTypes)/sizeof(commonTypes[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
    488342                "Each basic type kind should have a corresponding row in the combined type matrix"
    489343        );
    490 
    491         CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars )
    492                 : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) {
    493         }
    494 
    495         void CommonType_old::postvisit( VoidType * ) {}
    496 
    497         void CommonType_old::postvisit( BasicType * basicType ) {
    498                 if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) {
    499                         BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ otherBasic->get_kind() ];
    500                         if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) {
    501                                 result = new BasicType( basicType->tq | otherBasic->tq, newType );
    502                         } // if
    503                 } else if (  dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    504                         // use signed int in lieu of the enum/zero/one type
    505                         BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
    506                         if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {
    507                                 result = new BasicType( basicType->tq | type2->tq, newType );
    508                         } // if
    509                 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * > ( type2 ) ) {
    510                         const EnumDecl* enumDecl = enumInst->baseEnum;
    511                         if ( const Type* baseType = enumDecl->base ) {
    512                                 result = baseType->clone();
    513                         } else {
    514                                 BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
    515                                 if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {
    516                                         result = new BasicType( basicType->tq | type2->tq, newType );
    517                                 } // if
    518                         }
    519                 }
    520         }
    521 
    522         template< typename Pointer >
    523         void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) {
    524                 if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) {
    525                         OpenVarSet::const_iterator entry = openVars.find( var->get_name() );
    526                         if ( entry != openVars.end() ) {
    527                                 AssertionSet need, have;
    528                                 WidenMode widen( widenFirst, widenSecond );
    529                                 if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return;
    530                         }
    531                 }
    532                 result = voidPointer->clone();
    533                 result->tq |= otherPointer->tq;
    534         }
    535 
    536         void CommonType_old::postvisit( PointerType * pointerType ) {
    537                 if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) {
    538                         // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;
    539                         if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {
    540                                 getCommonWithVoidPointer( otherPointer, pointerType );
    541                         } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {
    542                                 getCommonWithVoidPointer( pointerType, otherPointer );
    543                         } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst )
    544                                            && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) {
    545                                 // std::cerr << "middle case" << std::endl;
    546                                 Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq;
    547                                 pointerType->get_base()->tq = Type::Qualifiers();
    548                                 otherPointer->get_base()->tq = Type::Qualifiers();
    549                                 AssertionSet have, need;
    550                                 OpenVarSet newOpen( openVars );
    551                                 if ( unifyExact( pointerType->get_base(), otherPointer->get_base(), env, have, need, newOpen, indexer ) ) {
    552                                         // std::cerr << "unifyExact success" << std::endl;
    553                                         if ( tq1 < tq2 ) {
    554                                                 result = pointerType->clone();
    555                                         } else {
    556                                                 result = otherPointer->clone();
    557                                         } // if
    558                                         strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2;
    559                                 } else {
    560                                         /// std::cerr << "place for ptr-to-type" << std::endl;
    561                                 } // if
    562                                 pointerType->get_base()->tq = tq1;
    563                                 otherPointer->get_base()->tq = tq2;
    564                         } // if
    565                 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    566                         result = pointerType->clone();
    567                         result->tq |= type2->tq;
    568                 } // if
    569         }
    570 
    571         void CommonType_old::postvisit( ArrayType * ) {}
    572 
    573         void CommonType_old::postvisit( ReferenceType * refType ) {
    574                 if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) {
    575                         // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;
    576                         // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl;
    577                         if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {
    578                                 getCommonWithVoidPointer( otherRef, refType );
    579                         } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {
    580                                 getCommonWithVoidPointer( refType, otherRef );
    581                         } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst )
    582                                            && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) {
    583                                 // std::cerr << "middle case" << std::endl;
    584                                 Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq;
    585                                 refType->get_base()->tq = Type::Qualifiers();
    586                                 otherRef->get_base()->tq = Type::Qualifiers();
    587                                 AssertionSet have, need;
    588                                 OpenVarSet newOpen( openVars );
    589                                 if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) {
    590                                         if ( tq1 < tq2 ) {
    591                                                 result = refType->clone();
    592                                         } else {
    593                                                 result = otherRef->clone();
    594                                         } // if
    595                                         strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2;
    596                                 } else {
    597                                         /// std::cerr << "place for ptr-to-type" << std::endl;
    598                                 } // if
    599                                 refType->get_base()->tq = tq1;
    600                                 otherRef->get_base()->tq = tq2;
    601                         } // if
    602                 } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    603                         result = refType->clone();
    604                         result->tq |= type2->tq;
    605                 } // if
    606         }
    607 
    608         void CommonType_old::postvisit( FunctionType * ) {}
    609         void CommonType_old::postvisit( StructInstType * ) {}
    610         void CommonType_old::postvisit( UnionInstType * ) {}
    611 
    612         void CommonType_old::postvisit( EnumInstType * enumInstType ) {
    613                 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    614                         // reuse BasicType, EnumInstType code by swapping type2 with enumInstType
    615                         result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );
    616                 } // if
    617         }
    618 
    619         void CommonType_old::postvisit( TraitInstType * ) {
    620         }
    621 
    622         void CommonType_old::postvisit( TypeInstType * inst ) {
    623                 if ( widenFirst ) {
    624                         const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() );
    625                         if ( nt ) {
    626                                 const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );
    627                                 if ( type->get_base() ) {
    628                                         Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq;
    629                                         AssertionSet have, need;
    630                                         OpenVarSet newOpen( openVars );
    631                                         type2->tq = Type::Qualifiers();
    632                                         type->get_base()->tq = tq1;
    633                                         if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) {
    634                                                 result = type2->clone();
    635                                                 result->tq = tq1 | tq2;
    636                                         } // if
    637                                         type2->tq = tq2;
    638                                         type->get_base()->tq = Type::Qualifiers();
    639                                 } // if
    640                         } // if
    641                 } // if
    642         }
    643 
    644         void CommonType_old::postvisit( TupleType * ) {}
    645         void CommonType_old::postvisit( VarArgsType * ) {}
    646 
    647         void CommonType_old::postvisit( ZeroType * zeroType ) {
    648                 if ( widenFirst ) {
    649                         if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {
    650                                 if ( widenSecond || zeroType->tq <= type2->tq ) {
    651                                         result = type2->clone();
    652                                         result->tq |= zeroType->tq;
    653                                 }
    654                         } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) {
    655                                 result = new BasicType( zeroType->tq, BasicType::SignedInt );
    656                                 result->tq |= type2->tq;
    657                         }
    658                 }
    659         }
    660 
    661         void CommonType_old::postvisit( OneType * oneType ) {
    662                 if ( widenFirst ) {
    663                         if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {
    664                                 if ( widenSecond || oneType->tq <= type2->tq ) {
    665                                         result = type2->clone();
    666                                         result->tq |= oneType->tq;
    667                                 }
    668                         } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    669                                 result = new BasicType( oneType->tq, BasicType::SignedInt );
    670                                 result->tq |= type2->tq;
    671                         }
    672                 }
    673         }
    674344
    675345        class CommonType_new final : public ast::WithShortCircuiting {
     
    700370                                else if (!widen.first) kind = basic->kind; // widen.second
    701371                                else if (!widen.second) kind = basic2->kind;
    702                                 else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
     372                                else kind = commonTypes[ basic->kind ][ basic2->kind ];
    703373                                // xxx - what does qualifiers even do here??
    704374                                if ( (basic->qualifiers >= basic2->qualifiers || widen.first)
     
    719389                                } else {
    720390                                        #warning remove casts when `commonTypes` moved to new AST
    721                                         ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
     391                                        ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
    722392                                        if (
    723393                                                ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
  • src/ResolvExpr/CommonType.hpp

    r0030b508 rfc12f05  
    1818#include "AST/Fwd.hpp"
    1919#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
    20 #include "TypeEnvironment.h"        // for AssertionSet, OpenVarSet
    2120#include "WidenMode.h"              // for WidenMode
    22 
    23 class Type;
    24 namespace SymTab {
    25         class Indexer;
    26 }
    2721
    2822namespace ResolvExpr {
    2923
    30 Type * commonType(
    31         Type * type1, Type * type2, bool widenFirst, bool widenSecond,
    32         const SymTab::Indexer & indexer, TypeEnvironment & env,
    33         const OpenVarSet & openVars );
    3424ast::ptr< ast::Type > commonType(
    3525        const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
  • src/ResolvExpr/ConversionCost.cc

    r0030b508 rfc12f05  
    2121
    2222#include "ResolvExpr/Cost.h"             // for Cost
    23 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2423#include "ResolvExpr/Unify.h"            // for typesCompatibleIgnoreQualifiers
    2524#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    26 #include "SymTab/Indexer.h"              // for Indexer
    27 #include "SynTree/Declaration.h"         // for TypeDecl, NamedTypeDecl
    28 #include "SynTree/Type.h"                // for Type, BasicType, TypeInstType
    29 
    3025
    3126namespace ResolvExpr {
    32 #if 0
    33         const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0,  0 };
    34         const Cost Cost::infinity =  Cost{ -1, -1, -1, -1, -1,  1, -1 };
    35         const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0,  0 };
    36         const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0,  0 };
    37         const Cost Cost::safe =      Cost{  0,  0,  1,  0,  0,  0,  0 };
    38         const Cost Cost::sign =      Cost{  0,  0,  0,  1,  0,  0,  0 };
    39         const Cost Cost::var =       Cost{  0,  0,  0,  0,  1,  0,  0 };
    40         const Cost Cost::spec =      Cost{  0,  0,  0,  0,  0, -1,  0 };
    41         const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  0,  1 };
    42 #endif
    4327
    4428#if 0
     
    4731#define PRINT(x)
    4832#endif
    49 
    50         Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,
    51                         const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    52                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    53                         PRINT( std::cerr << "type inst " << destAsTypeInst->name; )
    54                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
    55                                 if ( eqvClass->type ) {
    56                                         return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env );
    57                                 } else {
    58                                         return Cost::infinity;
    59                                 }
    60                         } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
    61                                 PRINT( std::cerr << " found" << std::endl; )
    62                                 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );
    63                                 // all typedefs should be gone by this point
    64                                 assert( type );
    65                                 if ( type->base ) {
    66                                         return conversionCost( src, type->base, srcIsLvalue, indexer, env )
    67                                                 + Cost::safe;
    68                                 } // if
    69                         } // if
    70                         PRINT( std::cerr << " not found" << std::endl; )
    71                 } // if
    72                 PRINT(
    73                         std::cerr << "src is ";
    74                         src->print( std::cerr );
    75                         std::cerr << std::endl << "dest is ";
    76                         dest->print( std::cerr );
    77                         std::cerr << std::endl << "env is" << std::endl;
    78                         env.print( std::cerr, 8 );
    79                 )
    80                 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    81                         PRINT( std::cerr << "compatible!" << std::endl; )
    82                         return Cost::zero;
    83                 } else if ( dynamic_cast< const VoidType * >( dest ) ) {
    84                         return Cost::safe;
    85                 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
    86                         PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    87                         return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){
    88                                 return ptrsAssignable( t1, t2, env );
    89                         });
    90                 } else {
    91                         PassVisitor<ConversionCost> converter(
    92                                 dest, srcIsLvalue, indexer, env,
    93                                 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))
    94                                         conversionCost );
    95                         src->accept( converter );
    96                         if ( converter.pass.get_cost() == Cost::infinity ) {
    97                                 return Cost::infinity;
    98                         } else {
    99                                 return converter.pass.get_cost() + Cost::zero;
    100                         } // if
    101                 } // if
    102         }
    103 
    104         static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue,
    105                         int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
    106                 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )
    107                 if ( diff > 0 ) {
    108                         // TODO: document this
    109                         Cost cost = convertToReferenceCost(
    110                                 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue,
    111                                 diff-1, indexer, env, func );
    112                         cost.incReference();
    113                         return cost;
    114                 } else if ( diff < -1 ) {
    115                         // TODO: document this
    116                         Cost cost = convertToReferenceCost(
    117                                 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue,
    118                                 diff+1, indexer, env, func );
    119                         cost.incReference();
    120                         return cost;
    121                 } else if ( diff == 0 ) {
    122                         const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src );
    123                         const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );
    124                         if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
    125                                 PRINT( std::cerr << "converting between references" << std::endl; )
    126                                 Type::Qualifiers tq1 = srcAsRef->base->tq;
    127                                 Type::Qualifiers tq2 = destAsRef->base->tq;
    128                                 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {
    129                                         PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
    130                                         if ( tq1 == tq2 ) {
    131                                                 // types are the same
    132                                                 return Cost::zero;
    133                                         } else {
    134                                                 // types are the same, except otherPointer has more qualifiers
    135                                                 return Cost::safe;
    136                                         }
    137                                 } else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
    138                                         int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env );
    139                                         PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )
    140                                         if ( assignResult > 0 ) {
    141                                                 return Cost::safe;
    142                                         } else if ( assignResult < 0 ) {
    143                                                 return Cost::unsafe;
    144                                         } // if
    145                                 } // if
    146                         } else {
    147                                 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
    148                                 PassVisitor<ConversionCost> converter(
    149                                         dest, srcIsLvalue, indexer, env,
    150                                         (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))
    151                                                 conversionCost );
    152                                 src->accept( converter );
    153                                 return converter.pass.get_cost();
    154                         } // if
    155                 } else {
    156                         const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );
    157                         assert( diff == -1 && destAsRef );
    158                         PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )
    159                         if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {
    160                                 PRINT( std::cerr << "converting compatible base type" << std::endl; )
    161                                 if ( srcIsLvalue ) {
    162                                         PRINT(
    163                                                 std::cerr << "lvalue to reference conversion" << std::endl;
    164                                                 std::cerr << src << " => " << destAsRef << std::endl;
    165                                         )
    166                                         // lvalue-to-reference conversion:  cv lvalue T => cv T &
    167                                         if ( src->tq == destAsRef->base->tq ) {
    168                                                 return Cost::reference; // cost needs to be non-zero to add cast
    169                                         } if ( src->tq < destAsRef->base->tq ) {
    170                                                 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
    171                                         } else {
    172                                                 return Cost::unsafe;
    173                                         } // if
    174                                 } else if ( destAsRef->base->get_const() ) {
    175                                         PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )
    176                                         // rvalue-to-const-reference conversion: T => const T &
    177                                         return Cost::safe;
    178                                 } else {
    179                                         PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )
    180                                         // rvalue-to-reference conversion: T => T &
    181                                         return Cost::unsafe;
    182                                 } // if
    183                         } // if
    184                         PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )
    185                 }
    186                 return Cost::infinity;
    187         }
    188 
    189         Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,
    190                         const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
    191                 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
    192                 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func );
    193                 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )
    194                 return cost;
    195         }
    196 
    197         ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
    198                 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {
    199         }
    20033
    20134        // GENERATED START, DO NOT EDIT
     
    22659        // GENERATED START, DO NOT EDIT
    22760        // GENERATED BY BasicTypes-gen.cc
    228         static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
     61        static const int costMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
    22962                /*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
    23063                /*      B */ {   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,  17,  16,  18,  17, },
     
    268101        // GENERATED END
    269102        static_assert(
    270                 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
     103                sizeof(costMatrix)/sizeof(costMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
    271104                "Missing row in the cost matrix"
    272105        );
     
    274107        // GENERATED START, DO NOT EDIT
    275108        // GENERATED BY BasicTypes-gen.cc
    276         static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
     109        static const int signMatrix[ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
    277110                /*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
    278111                /*      B */ {   0,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     
    315148        // GENERATED END
    316149        static_assert(
    317                 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
     150                sizeof(signMatrix)/sizeof(signMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,
    318151                "Missing row in the sign matrix"
    319152        );
    320 
    321         void ConversionCost::postvisit( const VoidType * ) {
    322                 cost = Cost::infinity;
    323         }
    324 
    325         // refactor for code resue
    326         void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) {
    327                 int tableResult = costMatrix[ src->kind ][ dest->kind ];
    328                 if ( tableResult == -1 ) {
    329                         cost = Cost::unsafe;
    330                 } else {
    331                         cost = Cost::zero;
    332                         cost.incSafe( tableResult );
    333                         cost.incSign( signMatrix[ src->kind ][ dest->kind ] );
    334                 } // if
    335         } // ConversionCost::conversionCostFromBasicToBasic
    336 
    337         void ConversionCost::postvisit(const BasicType * basicType) {
    338                 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    339                         conversionCostFromBasicToBasic(basicType, destAsBasic);
    340                 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) {
    341                         const EnumDecl * base_enum = enumInst->baseEnum;
    342                         if ( const Type * base = base_enum->base ) {
    343                                 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) {
    344                                         conversionCostFromBasicToBasic(basicType, enumBaseAstBasic);
    345                                 } else {
    346                                         cost = Cost::infinity;
    347                                 } // if
    348                         } else {
    349                                 cost = Cost::unsafe;
    350                         } // if
    351                 } // if
    352                 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t.
    353         }
    354 
    355         void ConversionCost::postvisit( const PointerType * pointerType ) {
    356                 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
    357                         PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )
    358                         Type::Qualifiers tq1 = pointerType->base->tq;
    359                         Type::Qualifiers tq2 = destAsPtr->base->tq;
    360                         if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
    361                                 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
    362                                 if ( tq1 == tq2 ) {
    363                                         // types are the same
    364                                         cost = Cost::zero;
    365                                 } else {
    366                                         // types are the same, except otherPointer has more qualifiers
    367                                         cost = Cost::safe;
    368                                 } // if
    369                         } else {
    370                                 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );
    371                                 PRINT( std::cerr << " :: " << assignResult << std::endl; )
    372                                 if ( assignResult > 0 && tq1 <= tq2 ) {
    373                                         // xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct?
    374                                         if ( tq1 == tq2 ) {
    375                                                 cost = Cost::safe;
    376                                         } else if ( tq1 < tq2 ) {
    377                                                 cost = Cost::safe+Cost::safe;
    378                                         }
    379                                 } else if ( assignResult < 0 ) {
    380                                         cost = Cost::unsafe;
    381                                 } // if
    382                                 // assignResult == 0 means Cost::Infinity
    383                         } // if
    384                         // case case for zero_t because it should not be possible to convert pointers to zero_t.
    385                 } // if
    386         }
    387 
    388         void ConversionCost::postvisit( const ArrayType * ) {}
    389 
    390         void ConversionCost::postvisit( const ReferenceType * refType ) {
    391                 // Note: dest can never be a reference, since it would have been caught in an earlier check
    392                 assert( ! dynamic_cast< const ReferenceType * >( dest ) );
    393                 // convert reference to rvalue: cv T1 & => T2
    394                 // recursively compute conversion cost from T1 to T2.
    395                 // cv can be safely dropped because of 'implicit dereference' behavior.
    396                 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env );
    397                 if ( refType->base->tq == dest->tq ) {
    398                         cost.incReference();  // prefer exact qualifiers
    399                 } else if ( refType->base->tq < dest->tq ) {
    400                         cost.incSafe(); // then gaining qualifiers
    401                 } else {
    402                         cost.incUnsafe(); // lose qualifiers as last resort
    403                 }
    404                 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )
    405         }
    406 
    407         void ConversionCost::postvisit( const FunctionType * ) {}
    408 
    409         void ConversionCost::postvisit( const EnumInstType * enumInst) {
    410                 const EnumDecl * enumDecl = enumInst -> baseEnum;
    411                 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum
    412                         cost = costFunc( enumType, dest, srcIsLvalue, indexer, env );
    413                 } else {
    414                         static Type::Qualifiers q;
    415                         static BasicType integer( q, BasicType::SignedInt );
    416                         cost = costFunc( &integer, dest, srcIsLvalue, indexer, env );  // safe if dest >= int
    417                 } // if
    418                 if ( cost < Cost::unsafe ) {
    419                                 cost.incSafe();
    420                 } // if
    421         }
    422 
    423         void ConversionCost::postvisit( const TraitInstType * ) {}
    424 
    425         void ConversionCost::postvisit( const TypeInstType * inst ) {
    426                 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {
    427                         cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env );
    428                 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    429                         if ( inst->name == destAsInst->name ) {
    430                                 cost = Cost::zero;
    431                         }
    432                 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) {
    433                         const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );
    434                         // all typedefs should be gone by this point
    435                         assert( type );
    436                         if ( type->base ) {
    437                                 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;
    438                         } // if
    439                 } // if
    440         }
    441 
    442         void ConversionCost::postvisit( const TupleType * tupleType ) {
    443                 Cost c = Cost::zero;
    444                 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) {
    445                         std::list< Type * >::const_iterator srcIt = tupleType->types.begin();
    446                         std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();
    447                         while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {
    448                                 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env );
    449                                 if ( newCost == Cost::infinity ) {
    450                                         return;
    451                                 } // if
    452                                 c += newCost;
    453                         } // while
    454                         if ( destIt != destAsTuple->types.end() ) {
    455                                 cost = Cost::infinity;
    456                         } else {
    457                                 cost = c;
    458                         } // if
    459                 } // if
    460         }
    461 
    462         void ConversionCost::postvisit( const VarArgsType * ) {
    463                 if ( dynamic_cast< const VarArgsType * >( dest ) ) {
    464                         cost = Cost::zero;
    465                 }
    466         }
    467 
    468         void ConversionCost::postvisit( const ZeroType * ) {
    469                 if ( dynamic_cast< const ZeroType * >( dest ) ) {
    470                         cost = Cost::zero;
    471                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    472                         // copied from visit(BasicType *) for signed int, but +1 for safe conversions
    473                         int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];
    474                         if ( tableResult == -1 ) {
    475                                 cost = Cost::unsafe;
    476                         } else {
    477                                 cost = Cost::zero;
    478                                 cost.incSafe( tableResult + 1 );
    479                                 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );
    480                         } // if
    481                 } else if ( dynamic_cast< const PointerType * >( dest ) ) {
    482                         cost = Cost::zero;
    483                         cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation
    484                 } // if
    485         }
    486 
    487         void ConversionCost::postvisit( const OneType * ) {
    488                 if ( dynamic_cast< const OneType * >( dest ) ) {
    489                         cost = Cost::zero;
    490                 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    491                         // copied from visit(BasicType *) for signed int, but +1 for safe conversions
    492                         int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];
    493                         if ( tableResult == -1 ) {
    494                                 cost = Cost::unsafe;
    495                         } else {
    496                                 cost = Cost::zero;
    497                                 cost.incSafe( tableResult + 1 );
    498                                 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );
    499                         } // if
    500                 } // if
    501         }
    502153
    503154namespace {
  • src/ResolvExpr/ConversionCost.h

    r0030b508 rfc12f05  
    2222#include "AST/Fwd.hpp"
    2323#include "AST/Pass.hpp"       // for WithShortCircuiting
    24 #include "Common/PassVisitor.h"
    25 #include "SynTree/Visitor.h"  // for Visitor
    26 #include "SynTree/SynTree.h"  // for Visitor Nodes
    2724
    2825namespace SymTab {
     
    3229namespace ResolvExpr {
    3330        class TypeEnvironment;
    34 
    35         Cost conversionCost(
    36                 const Type * src, const Type * dest, bool srcIsLvalue,
    37                 const SymTab::Indexer & indexer, const TypeEnvironment & env );
    38 
    39         typedef std::function<Cost(const Type *, const Type *, bool,
    40                 const SymTab::Indexer &, const TypeEnvironment &)> CostFunction;
    41 
    42         struct ConversionCost : public WithShortCircuiting {
    43           public:
    44                 ConversionCost( const Type * dest, bool srcIsLvalue,
    45                         const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction );
    46 
    47                 Cost get_cost() const { return cost; }
    48 
    49                 void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    50 
    51                 void postvisit( const VoidType * voidType );
    52                 void postvisit( const BasicType * basicType );
    53                 void postvisit( const PointerType * pointerType );
    54                 void postvisit( const ArrayType * arrayType );
    55                 void postvisit( const ReferenceType * refType );
    56                 void postvisit( const FunctionType * functionType );
    57                 void postvisit( const EnumInstType * aggregateUseType );
    58                 void postvisit( const TraitInstType * aggregateUseType );
    59                 void postvisit( const TypeInstType * aggregateUseType );
    60                 void postvisit( const TupleType * tupleType );
    61                 void postvisit( const VarArgsType * varArgsType );
    62                 void postvisit( const ZeroType * zeroType );
    63                 void postvisit( const OneType * oneType );
    64           protected:
    65                 const Type * dest;
    66                 bool srcIsLvalue;
    67                 const SymTab::Indexer &indexer;
    68                 Cost cost;
    69                 const TypeEnvironment &env;
    70                 CostFunction costFunc;
    71           private:
    72                 // refactor for code resue
    73                 void conversionCostFromBasicToBasic( const BasicType * src, const BasicType* dest );
    74         };
    75 
    76         typedef std::function<int(const Type *, const Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction;
    77         Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,
    78                 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func );
    7931
    8032// Some function pointer types, differ in return type.
  • src/ResolvExpr/CurrentObject.cc

    r0030b508 rfc12f05  
    3333#include "Common/utility.h"            // for toString
    3434#include "CurrentObject.h"
    35 #include "SynTree/Constant.h"          // for Constant
    36 #include "SynTree/Declaration.h"       // for ObjectDecl, Declaration, Struc...
    37 #include "SynTree/Expression.h"        // for InitAlternative, VariableExpr
    38 #include "SynTree/Initializer.h"       // for Designation, operator<<
    39 #include "SynTree/Type.h"              // for Type, StructInstType, UnionIns...
    40 #include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
    4135
    4236#if 0
     
    4539#define PRINT(x)
    4640#endif
    47 
    48 namespace ResolvExpr {
    49         template< typename AggrInst >
    50         TypeSubstitution makeGenericSubstitution( AggrInst * inst ) {
    51                 assert( inst );
    52                 assert( inst->get_baseParameters() );
    53                 std::list< TypeDecl * > baseParams = *inst->get_baseParameters();
    54                 std::list< Expression * > typeSubs = inst->get_parameters();
    55                 TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );
    56                 return subs;
    57         }
    58 
    59         TypeSubstitution makeGenericSubstitution( Type * type ) {
    60                 if ( StructInstType * inst = dynamic_cast< StructInstType * >( type ) ) {
    61                         return makeGenericSubstitution( inst );
    62                 } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( type ) ) {
    63                         return makeGenericSubstitution( inst );
    64                 } else {
    65                         return TypeSubstitution();
    66                 }
    67         }
    68 
    69         class MemberIterator {
    70         public:
    71                 virtual ~MemberIterator() {}
    72 
    73                 /// walks the current object using the given designators as a guide
    74                 virtual void setPosition( std::list< Expression * > & designators ) = 0;
    75 
    76                 /// retrieve the list of possible Type/Designation pairs for the current position in the currect object
    77                 virtual std::list<InitAlternative> operator*() const = 0;
    78 
    79                 /// true if the iterator is not currently at the end
    80                 virtual operator bool() const = 0;
    81 
    82                 /// moves the iterator by one member in the current object
    83                 virtual MemberIterator & bigStep() = 0;
    84 
    85                 /// moves the iterator by one member in the current subobject
    86                 virtual MemberIterator & smallStep() = 0;
    87 
    88                 /// the type of the current object
    89                 virtual Type * getType() = 0;
    90 
    91                 /// the type of the current subobject
    92                 virtual Type * getNext() = 0;
    93 
    94                 /// printing for debug
    95                 virtual void print( std::ostream & out, Indenter indent ) const = 0;
    96 
    97                 /// helper for operator*; aggregates must add designator to each init alternative, but
    98                 /// adding designators in operator* creates duplicates.
    99                 virtual std::list<InitAlternative> first() const = 0; // should be protected
    100         };
    101 
    102         std::ostream & operator<<(std::ostream & out, const MemberIterator & it) {
    103                 Indenter indenter;
    104                 it.print( out, indenter );
    105                 return out;
    106         }
    107 
    108         /// create a new MemberIterator that traverses a type correctly
    109         MemberIterator * createMemberIterator( Type * type );
    110 
    111         /// iterates "other" types, e.g. basic types, pointer types, etc. which do not change at list initializer entry
    112         class SimpleIterator : public MemberIterator {
    113         public:
    114                 SimpleIterator( Type * type ) : type( type ) {}
    115 
    116                 virtual void setPosition( std::list< Expression * > & designators ) {
    117                         assertf( designators.empty(), "simple iterator given non-empty designator..." ); // xxx - might be semantic error
    118                 }
    119 
    120                 virtual std::list<InitAlternative> operator*() const { return first(); }
    121                 virtual operator bool() const { return type; }
    122 
    123                 // big step is the same as small step
    124                 virtual MemberIterator & bigStep() { return smallStep(); }
    125                 virtual MemberIterator & smallStep() {
    126                         type = nullptr;  // type is nullified on increment since SimpleIterators do not have members
    127                         return *this;
    128                 }
    129 
    130                 virtual void print( std::ostream & out, __attribute__((unused)) Indenter indent ) const {
    131                         out << "SimpleIterator(" << type << ")";
    132                 }
    133 
    134                 virtual Type * getType() { return type; }
    135                 virtual Type * getNext() { return type; }
    136 
    137         protected:
    138                 virtual std::list<InitAlternative> first() const {
    139                         if ( type ) return std::list<InitAlternative>{ { type->clone(), new Designation( {} ) } };
    140                         else return std::list<InitAlternative>{};
    141                 }
    142         private:
    143                 Type * type = nullptr;
    144         };
    145 
    146         class ArrayIterator : public MemberIterator {
    147         public:
    148                 ArrayIterator( ArrayType * at ) : array( at ) {
    149                         PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
    150                         base = at->base;
    151                         memberIter = createMemberIterator( base );
    152                         if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=: " );
    153                         setSize( at->dimension );
    154                 }
    155 
    156                 ~ArrayIterator() {
    157                         delete memberIter;
    158                 }
    159 
    160         private:
    161                 void setSize( Expression * expr ) {
    162                         auto res = eval( expr );
    163                         if (res.second) {
    164                                 size = res.first;
    165                         } else {
    166                                 SemanticError( expr->location, toString("Array designator must be a constant expression: ", expr) );
    167                         }
    168                 }
    169 
    170         public:
    171                 void setPosition( Expression * expr ) {
    172                         // need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions
    173                         auto arg = eval( expr );
    174                         index = arg.first;
    175                         return;
    176 
    177                         // if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
    178                         //      try {
    179                         //              index = constExpr->intValue();
    180                         //      } catch( SemanticErrorException & ) {
    181                         //              SemanticError( expr, "Constant expression of non-integral type in array designator: " );
    182                         //      }
    183                         // } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    184                         //      setPosition( castExpr->get_arg() );
    185                         // } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
    186                         //      EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );
    187                         //      assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );
    188                         //      long long int value;
    189                         //      if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
    190                         //              index = value;
    191                         //      }
    192                         // } else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {
    193                         //      index = 0; // xxx - get actual sizeof/alignof value?
    194                         // } else {
    195                         //      assertf( false, "4 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
    196                         // }
    197                 }
    198 
    199                 virtual void setPosition( std::list< Expression * > & designators ) {
    200                         if ( ! designators.empty() ) {
    201                                 setPosition( designators.front() );
    202                                 designators.pop_front();
    203                                 memberIter->setPosition( designators );
    204                         }
    205                 }
    206 
    207                 virtual std::list<InitAlternative> operator*() const {
    208                         return first();
    209                 }
    210 
    211                 virtual operator bool() const { return index < size; }
    212 
    213                 virtual MemberIterator & bigStep() {
    214                         PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    215                         ++index;
    216                         delete memberIter;
    217                         if ( index < size ) memberIter = createMemberIterator( base );
    218                         else memberIter = nullptr;
    219                         return *this;
    220                 }
    221 
    222                 virtual MemberIterator & smallStep() {
    223                         PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    224                         if ( memberIter ) {
    225                                 PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
    226                                 memberIter->smallStep();
    227                                 if ( *memberIter ) {
    228                                         PRINT( std::cerr << "has valid member iter" << std::endl; )
    229                                         return *this;
    230                                 }
    231                         }
    232                         return bigStep();
    233                 }
    234 
    235                 virtual Type * getType() { return array; }
    236                 virtual Type * getNext() { return base; }
    237 
    238                 virtual std::list<InitAlternative> first() const {
    239                         PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
    240                         if ( memberIter && *memberIter ) {
    241                                 std::list<InitAlternative> ret = memberIter->first();
    242                                 for ( InitAlternative & alt : ret ) {
    243                                         alt.designation->get_designators().push_front( new ConstantExpr( Constant::from_ulong( index ) ) );
    244                                 }
    245                                 return ret;
    246                         }
    247                         return std::list<InitAlternative>();
    248                 }
    249 
    250                 virtual void print( std::ostream & out, Indenter indent ) const {
    251                         out << "ArrayIterator(Array of " << base << ")";
    252                         if ( memberIter ) {
    253                                 Indenter childIndent = indent+1;
    254                                 out << std::endl << childIndent;
    255                                 memberIter->print( out, childIndent );
    256                         }
    257                 }
    258 
    259         private:
    260                 ArrayType * array = nullptr;
    261                 Type * base = nullptr;
    262                 size_t index = 0;
    263                 size_t size = 0;
    264                 MemberIterator * memberIter = nullptr;
    265         };
    266 
    267         class AggregateIterator : public MemberIterator {
    268         public:
    269                 typedef std::list<Declaration *> MemberList;
    270                 typedef MemberList::const_iterator iterator;
    271                 std::string kind = ""; // for debug
    272                 std::string name;
    273                 Type * inst = nullptr;
    274                 const MemberList & members;
    275                 iterator curMember;
    276                 bool atbegin = true; // false at first {small,big}Step -- this aggr type is only added to the possibilities at the beginning
    277                 Type * curType = nullptr;
    278                 MemberIterator * memberIter = nullptr;
    279                 mutable TypeSubstitution sub;
    280 
    281                 AggregateIterator( const std::string & kind, const std::string & name, Type * inst, const MemberList & members ) : kind( kind ), name( name ), inst( inst ), members( members ), curMember( members.begin() ), sub( makeGenericSubstitution( inst ) ) {
    282                         PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
    283                         init();
    284                 }
    285 
    286                 virtual ~AggregateIterator() {
    287                         delete memberIter;
    288                 }
    289 
    290                 bool init() {
    291                         PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
    292                         if ( curMember != members.end() ) {
    293                                 if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( *curMember ) ) {
    294                                         PRINT( std::cerr << "incremented to field: " << field << std::endl; )
    295                                         curType = field->get_type();
    296                                         memberIter = createMemberIterator( curType );
    297                                         return true;
    298                                 }
    299                         }
    300                         return false;
    301                 }
    302 
    303                 virtual std::list<InitAlternative> operator*() const {
    304                         if (memberIter && *memberIter) {
    305                                 std::list<InitAlternative> ret = memberIter->first();
    306                                 PRINT( std::cerr << "sub: " << sub << std::endl; )
    307                                 for ( InitAlternative & alt : ret ) {
    308                                         PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    309                                         alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );
    310                                         // need to substitute for generic types, so that casts are to concrete types
    311                                         PRINT( std::cerr << "  type is: " << alt.type; )
    312                                         sub.apply( alt.type ); // also apply to designation??
    313                                         PRINT( std::cerr << " ==> " << alt.type << std::endl; )
    314                                 }
    315                                 return ret;
    316                         }
    317                         return std::list<InitAlternative>();
    318                 }
    319 
    320                 virtual void setPosition( std::list< Expression * > & designators ) {
    321                         if ( ! designators.empty() ) {
    322                                 if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( designators.front() ) ) {
    323                                         for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
    324                                                 if ( *curMember == varExpr->get_var() ) {
    325                                                         designators.pop_front();
    326                                                         delete memberIter;
    327                                                         memberIter = createMemberIterator( varExpr->get_result() );
    328                                                         curType = varExpr->get_result();
    329                                                         atbegin = curMember == members.begin() && designators.empty(); // xxx - is this the right condition for atbegin??
    330                                                         memberIter->setPosition( designators );
    331                                                         return;
    332                                                 } // if
    333                                         } // for
    334                                         assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    335                                 } else {
    336                                         assertf( false, "3 bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() );
    337                                 } // if
    338                         } // if
    339                 }
    340 
    341                 virtual MemberIterator & smallStep() {
    342                         PRINT( std::cerr << "smallStep in " << kind << std::endl; )
    343                         atbegin = false;
    344                         if ( memberIter ) {
    345                                 PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
    346                                 memberIter->smallStep();
    347                                 if ( *memberIter ) {
    348                                         PRINT( std::cerr << "success!" << std::endl; )
    349                                         return *this;
    350                                 }
    351                         }
    352                         return bigStep();
    353                 }
    354 
    355                 virtual Type * getType() { return inst; }
    356                 virtual Type * getNext() {
    357                         if ( memberIter && *memberIter ) return memberIter->getType(); // xxx - ??? recursive call???
    358                         return nullptr;
    359                 }
    360 
    361                 virtual std::list<InitAlternative> first() const {
    362                         std::list<InitAlternative> ret;
    363                         PRINT( std::cerr << "first " << kind << std::endl; )
    364                         if ( memberIter && *memberIter ) { // might not need *memberIter??
    365                                 PRINT( std::cerr << "adding children" << std::endl; )
    366                                 ret = memberIter->first();
    367                                 for ( InitAlternative & alt : ret ) {
    368                                         PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    369                                         alt.designation->get_designators().push_front( new VariableExpr( strict_dynamic_cast< ObjectDecl * >( *curMember ) ) );
    370                                 }
    371                         }
    372                         if ( atbegin ) {
    373                                 // xxx - what about case of empty struct??
    374                                 // only add self if at the very beginning of the structure
    375                                 PRINT( std::cerr << "adding self" << std::endl; )
    376                                 ret.push_front( { inst->clone(), new Designation( {} ) } );
    377                         }
    378                         return ret;
    379                 }
    380 
    381                 virtual void print( std::ostream & out, Indenter indent ) const {
    382                         out << kind << "(" << name << ")";
    383                         if ( memberIter ) {
    384                                 Indenter childIndent = indent+1;
    385                                 out << std::endl << childIndent;
    386                                 memberIter->print( out, childIndent );
    387                         }
    388                 }
    389         };
    390 
    391         class UnionIterator : public AggregateIterator {
    392         public:
    393                 UnionIterator( UnionInstType * inst ) : AggregateIterator( "UnionIterator", inst->get_name(), inst, inst->get_baseUnion()->get_members() ) {}
    394 
    395                 virtual operator bool() const { return (memberIter && *memberIter); }
    396                 virtual MemberIterator & bigStep() {
    397                         // unions only initialize one member
    398                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    399                         atbegin = false;
    400                         delete memberIter;
    401                         memberIter = nullptr;
    402                         curType = nullptr;
    403                         curMember = members.end();
    404                         return *this;
    405                 }
    406         };
    407 
    408         class StructIterator : public AggregateIterator {
    409         public:
    410                 StructIterator( StructInstType * inst ) : AggregateIterator( "StructIterator", inst->get_name(), inst, inst->get_baseStruct()->get_members() ) {}
    411 
    412                 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }
    413 
    414                 virtual MemberIterator & bigStep() {
    415                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    416                         atbegin = false;
    417                         delete memberIter;
    418                         memberIter = nullptr;
    419                         curType = nullptr;
    420                         for ( ; curMember != members.end(); ) {
    421                                 ++curMember;
    422                                 if ( init() ) {
    423                                         return *this;
    424                                 }
    425                         }
    426                         return *this;
    427                 }
    428         };
    429 
    430         class TupleIterator : public AggregateIterator {
    431         public:
    432                 TupleIterator( TupleType * inst ) : AggregateIterator( "TupleIterator", toString("Tuple", inst->size()), inst, inst->get_members() ) {}
    433 
    434                 virtual operator bool() const { return curMember != members.end() || (memberIter && *memberIter); }
    435 
    436                 virtual MemberIterator & bigStep() {
    437                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    438                         atbegin = false;
    439                         delete memberIter;
    440                         memberIter = nullptr;
    441                         curType = nullptr;
    442                         for ( ; curMember != members.end(); ) {
    443                                 ++curMember;
    444                                 if ( init() ) {
    445                                         return *this;
    446                                 }
    447                         }
    448                         return *this;
    449                 }
    450         };
    451 
    452         MemberIterator * createMemberIterator( Type * type ) {
    453                 if ( ReferenceToType * aggr = dynamic_cast< ReferenceToType * >( type ) ) {
    454                         if ( StructInstType * sit = dynamic_cast< StructInstType * >( aggr ) ) {
    455                                 return new StructIterator( sit );
    456                         } else if ( UnionInstType * uit = dynamic_cast< UnionInstType * >( aggr ) ) {
    457                                 return new UnionIterator( uit );
    458                         } else {
    459                                 assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() );
    460                                 return new SimpleIterator( type );
    461                         }
    462                 } else if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
    463                         return new ArrayIterator( at );
    464                 } else if ( TupleType * tt = dynamic_cast< TupleType * >( type ) ) {
    465                         return new TupleIterator( tt );
    466                 } else {
    467                         return new SimpleIterator( type );
    468                 }
    469         }
    470 
    471         CurrentObject::CurrentObject() {}
    472         CurrentObject::CurrentObject( Type * type ) {
    473                 objStack.push( new SimpleIterator( type ) );
    474         }
    475 
    476 
    477         void CurrentObject::setNext( Designation * designation ) {
    478                 assertf( ! objStack.empty(), "obj stack empty in setNext" );
    479                 PRINT( std::cerr << "____setNext" << designation << std::endl; )
    480                 objStack.top()->setPosition( designation->get_designators() );
    481         }
    482 
    483         Designation * CurrentObject::findNext( Designation * designation ) {
    484                 typedef std::list< Expression * > DesignatorChain;
    485                 PRINT( std::cerr << "___findNext" << std::endl; )
    486                 // find all the d's
    487                 std::list<DesignatorChain> desigAlts{ { } }, newDesigAlts;
    488                 std::list<Type *> curTypes { (objStack.top())->getType() }, newTypes;
    489                 for ( Expression * expr : designation->get_designators() ) {
    490                         PRINT( std::cerr << "____untyped: " << expr << std::endl; )
    491                         std::list<DesignatorChain>::iterator dit = desigAlts.begin();
    492                         if ( NameExpr * nexpr = dynamic_cast<NameExpr *>(expr) ) {
    493                                 for ( Type * t : curTypes ) {
    494                                         assert( dit != desigAlts.end() );
    495                                         DesignatorChain & d = *dit;
    496                                         PRINT( std::cerr << "____actual: " << t << std::endl; )
    497                                         ReferenceToType * refType = dynamic_cast<ReferenceToType *>(t);
    498                                         std::list<Declaration *> members;
    499                                         if ( refType ) {
    500                                                 refType->lookup( nexpr->get_name(), members ); // concatenate identical field name
    501                                                 // xxx - need to also include anonymous members in this somehow...
    502                                                 for ( Declaration * mem: members ) {
    503                                                         if ( ObjectDecl * field = dynamic_cast<ObjectDecl *>(mem) ) {
    504                                                                 PRINT( std::cerr << "____alt: " << field->get_type() << std::endl; )
    505                                                                 DesignatorChain newD = d;
    506                                                                 newD.push_back( new VariableExpr( field ) );
    507                                                                 newDesigAlts.push_back( newD );
    508                                                                 newTypes.push_back( field->get_type() );
    509                                                         } // if
    510                                                 } // for
    511                                         } // if
    512                                         ++dit;
    513                                 } // for
    514                         } else {
    515                                 for ( Type * t : curTypes ) {
    516                                         assert( dit != desigAlts.end() );
    517                                         DesignatorChain & d = *dit;
    518                                         if ( ArrayType * at = dynamic_cast< ArrayType * > ( t ) ) {
    519                                                 PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
    520                                                 d.push_back( expr );
    521                                                 newDesigAlts.push_back( d );
    522                                                 newTypes.push_back( at->get_base() );
    523                                         }
    524                                         ++dit;
    525                                 } // for
    526                         } // if
    527                         desigAlts = newDesigAlts;
    528                         newDesigAlts.clear();
    529                         curTypes = newTypes;
    530                         newTypes.clear();
    531                         assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
    532                 } // for
    533                 if ( desigAlts.size() > 1 ) {
    534                         SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
    535                 } else if ( desigAlts.size() == 0 ) {
    536                         SemanticError( designation, "No reasonable alternatives for designation: " );
    537                 }
    538                 DesignatorChain & d = desigAlts.back();
    539                 PRINT( for ( Expression * expr : d ) {
    540                         std::cerr << "____desig: " << expr << std::endl;
    541                 } ) // for
    542                 assertf( ! curTypes.empty(), "empty designator chosen");
    543 
    544                 // set new designators
    545                 assertf( ! objStack.empty(), "empty object stack when setting designation" );
    546                 Designation * actualDesignation = new Designation( d );
    547                 objStack.top()->setPosition( d ); // destroys d
    548                 return actualDesignation;
    549         }
    550 
    551         void CurrentObject::increment() {
    552                 PRINT( std::cerr << "____increment" << std::endl; )
    553                 if ( ! objStack.empty() ) {
    554                         PRINT( std::cerr << *objStack.top() << std::endl; )
    555                         objStack.top()->smallStep();
    556                 }
    557         }
    558 
    559         void CurrentObject::enterListInit() {
    560                 PRINT( std::cerr << "____entering list init" << std::endl; )
    561                 assertf( ! objStack.empty(), "empty obj stack entering list init" );
    562                 Type * type = objStack.top()->getNext();
    563                 if ( type ) {
    564                         objStack.push( createMemberIterator( type ) );
    565                 } else {
    566                         assertf( false, "not sure about this case..." );
    567                 }
    568         }
    569 
    570         void CurrentObject::exitListInit() {
    571                 PRINT( std::cerr << "____exiting list init" << std::endl; )
    572                 assertf( ! objStack.empty(), "objstack empty" );
    573                 delete objStack.top();
    574                 objStack.pop();
    575                 if ( ! objStack.empty() ) {
    576                         PRINT( std::cerr << *objStack.top() << std::endl; )
    577                         objStack.top()->bigStep();
    578                 }
    579         }
    580 
    581         std::list< InitAlternative > CurrentObject::getOptions() {
    582                 PRINT( std::cerr << "____getting current options" << std::endl; )
    583                 assertf( ! objStack.empty(), "objstack empty in getOptions" );
    584                 return **objStack.top();
    585         }
    586 
    587         Type * CurrentObject::getCurrentType() {
    588                 PRINT( std::cerr << "____getting current type" << std::endl; )
    589                 assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
    590                 return objStack.top()->getNext();
    591         }
    592 } // namespace ResolvExpr
    59341
    59442namespace ast {
     
    1064512                                        } else if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
    1065513                                                auto nexpr = dynamic_cast< const NameExpr *>( expr );
    1066                                                 auto res = eval( nexpr );
    1067514                                                for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
    1068515                                                        if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
     
    1070517                                                                d2.emplace_back( new VariableExpr{ expr->location, field } );
    1071518                                                                newDesigAlts.emplace_back( std::move( d2 ) );
    1072                                                                 // newTypes.emplace_back( field->type );
    1073519                                                                newTypes.emplace_back( at->base );
    1074520                                                        }
    1075521                                                }
    1076 
    1077                                                 // d.emplace_back( expr );
    1078                                                 // newDesigAlts.emplace_back( d );
    1079                                                 // newTypes.emplace_back( at->base );
    1080522                                        }
    1081523
  • src/ResolvExpr/FindOpenVars.cc

    r0030b508 rfc12f05  
    1616#include "FindOpenVars.h"
    1717
    18 #include <list>                   // for _List_const_iterator, list<>::const...
    19 #include <map>                    // for map<>::mapped_type
    20 
    2118#include "AST/Pass.hpp"
    2219#include "AST/Type.hpp"
    2320#include "AST/TypeEnvironment.hpp"
    24 #include "Common/PassVisitor.h"
    25 #include "SynTree/Declaration.h"  // for TypeDecl, DeclarationWithType (ptr ...
    26 #include "SynTree/Type.h"         // for Type, Type::ForallList, ArrayType
    2721
    2822#include <iostream>
    2923
    3024namespace ResolvExpr {
    31         struct FindOpenVars_old : public WithGuards {
    32                 FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
    33 
    34                 void previsit( const PointerType * pointerType );
    35                 void previsit( const ArrayType * arrayType );
    36                 void previsit( const FunctionType * functionType );
    37                 void previsit( const TupleType * tupleType );
    38 
    39                 void common_action( const Type *type );
    40 
    41                 OpenVarSet &openVars, &closedVars;
    42                 AssertionSet &needAssertions, &haveAssertions;
    43                 bool nextIsOpen;
    44         };
    45 
    46         void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {
    47                 PassVisitor<FindOpenVars_old> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );
    48                 type->accept( finder );
    49         }
    50 
    51         FindOpenVars_old::FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen )
    52                 : openVars( openVars ), closedVars( closedVars ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), nextIsOpen( firstIsOpen ) {
    53         }
    54 
    55         void FindOpenVars_old::common_action( const Type * type ) {
    56                 if ( nextIsOpen ) {
    57                         for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
    58                                 openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
    59                                 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
    60                                         needAssertions[ *assert ].isUsed = false;
    61                                 }
    62 ///       cloneAll( (*i)->get_assertions(), needAssertions );
    63 ///       needAssertions.insert( needAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );
    64                         }
    65                 } else {
    66                         for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
    67                                 closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
    68                                 for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
    69                                         haveAssertions[ *assert ].isUsed = false;
    70                                 }
    71 ///       cloneAll( (*i)->get_assertions(), haveAssertions );
    72 ///       haveAssertions.insert( haveAssertions.end(), (*i)->get_assertions().begin(), (*i)->get_assertions().end() );
    73                         } // for
    74                 } // if
    75 ///   std::cerr << "type is ";
    76 ///   type->print( std::cerr );
    77 ///   std::cerr << std::endl << "need is" << std::endl;
    78 ///   printAssertionSet( needAssertions, std::cerr );
    79 ///   std::cerr << std::endl << "have is" << std::endl;
    80 ///   printAssertionSet( haveAssertions, std::cerr );
    81         }
    82 
    83         void FindOpenVars_old::previsit(const PointerType * pointerType) {
    84                 common_action( pointerType );
    85         }
    86 
    87         void FindOpenVars_old::previsit(const ArrayType * arrayType) {
    88                 common_action( arrayType );
    89         }
    90 
    91         void FindOpenVars_old::previsit(const FunctionType * functionType) {
    92                 common_action( functionType );
    93                 nextIsOpen = ! nextIsOpen;
    94                 GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
    95         }
    96 
    97         void FindOpenVars_old::previsit(const TupleType * tupleType) {
    98                 common_action( tupleType );
    99         }
    10025
    10126        namespace {
  • src/ResolvExpr/FindOpenVars.h

    r0030b508 rfc12f05  
    1717
    1818#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
    19 #include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
    2019
    21 class Type;
    2220namespace ast {
    2321        class Type;
     
    2523
    2624namespace ResolvExpr {
    27         // Updates open and closed variables and their associated assertions
    28         void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
    29 
    3025        enum FirstMode { FirstClosed, FirstOpen };
    3126
  • src/ResolvExpr/PolyCost.cc

    r0030b508 rfc12f05  
    1818#include "AST/Type.hpp"
    1919#include "AST/TypeEnvironment.hpp"
    20 #include "Common/PassVisitor.h"
    21 #include "SymTab/Indexer.h"   // for Indexer
    22 #include "SynTree/Type.h"     // for TypeInstType, Type
    23 #include "TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    2420
    2521namespace ResolvExpr {
    26         struct PolyCost {
    27                 PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer );
    28 
    29                 void previsit( TypeInstType * aggregateUseType );
    30                 int result;
    31                 const TypeEnvironment &tenv;
    32                 const SymTab::Indexer &indexer;
    33         };
    34 
    35         int polyCost( Type *type, const TypeEnvironment & env, const SymTab::Indexer &indexer ) {
    36                 PassVisitor<PolyCost> coster( env, indexer );
    37                 type->accept( coster );
    38                 return (coster.pass.result > 0) ? 1 : 0;
    39         }
    40 
    41         PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), tenv( env ), indexer( indexer ) {
    42         }
    43 
    44         void PolyCost::previsit(TypeInstType * typeInst) {
    45                 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) {
    46                         if ( eqvClass->type ) {
    47                                 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) {
    48                                         if ( indexer.lookupType( otherTypeInst->name ) ) {
    49                                                 // bound to opaque type
    50                                                 result += 1;
    51                                         } // if
    52                                 } else {
    53                                         // bound to concrete type
    54                                         result += 1;
    55                                 } // if
    56                         } // if
    57                 } // if
    58         }
    5922
    6023// TODO: When the old PolyCost is torn out get rid of the _new suffix.
  • src/ResolvExpr/PtrsAssignable.cc

    r0030b508 rfc12f05  
    1919#include "AST/Type.hpp"
    2020#include "AST/TypeEnvironment.hpp"
    21 #include "Common/PassVisitor.h"
    22 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    23 #include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
    24 #include "SynTree/Visitor.h"             // for Visitor
    25 
    2621
    2722namespace ResolvExpr {
    28         struct PtrsAssignable : public WithShortCircuiting {
    29                 PtrsAssignable( const Type * dest, const TypeEnvironment &env );
    30 
    31                 int get_result() const { return result; }
    32 
    33                 void previsit( const Type * ) { visit_children = false; }
    34 
    35                 void postvisit( const VoidType * voidType );
    36                 void postvisit( const BasicType * basicType );
    37                 void postvisit( const PointerType * pointerType );
    38                 void postvisit( const ArrayType * arrayType );
    39                 void postvisit( const FunctionType * functionType );
    40                 void postvisit( const StructInstType * inst );
    41                 void postvisit( const UnionInstType * inst );
    42                 void postvisit( const EnumInstType * inst );
    43                 void postvisit( const TraitInstType * inst );
    44                 void postvisit( const TypeInstType * inst );
    45                 void postvisit( const TupleType * tupleType );
    46                 void postvisit( const VarArgsType * varArgsType );
    47                 void postvisit( const ZeroType * zeroType );
    48                 void postvisit( const OneType * oneType );
    49           private:
    50                 const Type * dest;
    51                 int result;
    52                 const TypeEnvironment &env;
    53         };
    54 
    55         int ptrsAssignable( const Type *src, const Type * dest, const TypeEnvironment &env ) {
    56                 // std::cerr << "assignable: " << src << " | " << dest << std::endl;
    57                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {
    58                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    59                                 return ptrsAssignable( src, eqvClass->type, env );
    60                         } // if
    61                 } // if
    62                 if ( dynamic_cast< const VoidType* >( dest ) ) {
    63                         // void * = T * for any T is unsafe
    64                         // xxx - this should be safe, but that currently breaks the build
    65                         return -1;
    66                 } else {
    67                         PassVisitor<PtrsAssignable> ptrs( dest, env );
    68                         src->accept( ptrs );
    69                         return ptrs.pass.get_result();
    70                 } // if
    71         }
    72 
    73         PtrsAssignable::PtrsAssignable( const Type * dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}
    74 
    75         void PtrsAssignable::postvisit( const VoidType * ) {
    76                 // T * = void * is disallowed - this is a change from C, where any
    77                 // void * can be assigned or passed to a non-void pointer without a cast.
    78         }
    79 
    80         void PtrsAssignable::postvisit( const BasicType * ) {}
    81         void PtrsAssignable::postvisit( const PointerType * ) {}
    82         void PtrsAssignable::postvisit( const ArrayType * ) {}
    83         void PtrsAssignable::postvisit( const FunctionType * ) {}
    84 
    85         void PtrsAssignable::postvisit( const StructInstType * ) {}
    86         void PtrsAssignable::postvisit( const UnionInstType * ) {}
    87 
    88         void PtrsAssignable::postvisit( const EnumInstType * ) {
    89                 if ( dynamic_cast< const BasicType* >( dest ) ) {
    90                         // int * = E *, etc. is safe. This isn't technically correct, as each
    91                         // enum has one basic type that it is compatible with, an that type can
    92                         // differ from enum to enum. Without replicating GCC's internal logic,
    93                         // there is no way to know which type this particular enum is compatible
    94                         // with, so punt on this for now.
    95                         result = 1;
    96                 }
    97         }
    98 
    99         void PtrsAssignable::postvisit(  const TraitInstType * ) {}
    100         void PtrsAssignable::postvisit( const TypeInstType * inst ) {
    101                 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {
    102                         if ( eqvClass->type ) {
    103                                 // T * = S * for any S depends on the type bound to T
    104                                 result = ptrsAssignable( eqvClass->type, dest, env );
    105                         }
    106                 } // if
    107         }
    108 
    109         void PtrsAssignable::postvisit( const TupleType * ) {}
    110         void PtrsAssignable::postvisit( const VarArgsType * ) {}
    111         void PtrsAssignable::postvisit( const ZeroType * ) {}
    112         void PtrsAssignable::postvisit( const OneType * ) {}
    11323
    11424// TODO: Get rid of the `_new` suffix when the old version is removed.
  • src/ResolvExpr/PtrsCastable.cc

    r0030b508 rfc12f05  
    2020#include "AST/Type.hpp"
    2121#include "AST/TypeEnvironment.hpp"
    22 #include "Common/PassVisitor.h"
    2322#include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable
    24 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
    25 #include "SymTab/Indexer.h"              // for Indexer
    26 #include "SynTree/Declaration.h"         // for TypeDecl, TypeDecl::Kind::Ftype
    27 #include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
    28 #include "SynTree/Visitor.h"             // for Visitor
    2923
    3024namespace ResolvExpr {
    31         struct PtrsCastable_old : public WithShortCircuiting  {
    32           public:
    33                 PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );
    34 
    35                 int get_result() const { return result; }
    36 
    37                 void previsit( const Type * ) { visit_children = false; }
    38 
    39                 void postvisit( const VoidType * voidType );
    40                 void postvisit( const BasicType * basicType );
    41                 void postvisit( const PointerType * pointerType );
    42                 void postvisit( const ArrayType * arrayType );
    43                 void postvisit( const FunctionType * functionType );
    44                 void postvisit( const StructInstType * inst );
    45                 void postvisit( const UnionInstType * inst );
    46                 void postvisit( const EnumInstType * inst );
    47                 void postvisit( const TraitInstType * inst );
    48                 void postvisit( const TypeInstType * inst );
    49                 void postvisit( const TupleType * tupleType );
    50                 void postvisit( const VarArgsType * varArgsType );
    51                 void postvisit( const ZeroType * zeroType );
    52                 void postvisit( const OneType * oneType );
    53           private:
    54                 const Type * dest;
    55                 int result;
    56                 const TypeEnvironment &env;
    57                 const SymTab::Indexer &indexer;
    58         };
    59 
    60         namespace {
    61                 int objectCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    62                         if ( dynamic_cast< const FunctionType* >( src ) ) {
    63                                 return -1;
    64                         } else if ( const TypeInstType * typeInst = dynamic_cast< const TypeInstType* >( src ) ) {
    65                                 if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->name ) ) {
    66                                         if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl* >( ntDecl ) ) {
    67                                                 if ( tyDecl->kind == TypeDecl::Ftype ) {
    68                                                         return -1;
    69                                                 } // if
    70                                         } //if
    71                                 } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {
    72                                         if ( eqvClass->data.kind == TypeDecl::Ftype ) {
    73                                                 return -1;
    74                                         } // if
    75                                 } // if
    76                         } //if
    77                         return 1;
    78                 }
    79                 int functionCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    80                         return -1 * objectCast( src, env, indexer );  // reverse the sense of objectCast
    81                 }
    82         }
    83 
    84         int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    85                 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {
    86                         if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    87                                 // xxx - should this be ptrsCastable?
    88                                 return ptrsAssignable( src, eqvClass->type, env );
    89                         } // if
    90                 } // if
    91                 if ( dynamic_cast< const VoidType* >( dest ) ) {
    92                         return objectCast( src, env, indexer );
    93                 } else {
    94                         PassVisitor<PtrsCastable_old> ptrs( dest, env, indexer );
    95                         src->accept( ptrs );
    96                         return ptrs.pass.get_result();
    97                 } // if
    98         }
    99 
    100         PtrsCastable_old::PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer )
    101                 : dest( dest ), result( 0 ), env( env ), indexer( indexer )     {
    102         }
    103 
    104         void PtrsCastable_old::postvisit( const VoidType * ) {
    105                 result = objectCast( dest, env, indexer );
    106         }
    107 
    108         void PtrsCastable_old::postvisit( const BasicType * ) {
    109                 result = objectCast( dest, env, indexer );
    110         }
    111 
    112         void PtrsCastable_old::postvisit( const PointerType * ) {
    113                 result = objectCast( dest, env, indexer );
    114         }
    115 
    116         void PtrsCastable_old::postvisit( const ArrayType * ) {
    117                 result = objectCast( dest, env, indexer );
    118         }
    119 
    120         void PtrsCastable_old::postvisit( const FunctionType * ) {
    121                 // result = -1;
    122                 result = functionCast( dest, env, indexer );
    123         }
    124 
    125         void PtrsCastable_old::postvisit( const StructInstType * ) {
    126                 result = objectCast( dest, env, indexer );
    127         }
    128 
    129         void PtrsCastable_old::postvisit( const UnionInstType * ) {
    130                 result = objectCast( dest, env, indexer );
    131         }
    132 
    133         void PtrsCastable_old::postvisit( const EnumInstType * ) {
    134                 if ( dynamic_cast< const EnumInstType * >( dest ) ) {
    135                         result = 1;
    136                 } else if ( const BasicType * bt = dynamic_cast< const BasicType * >( dest ) ) {
    137                         if ( bt->kind == BasicType::SignedInt ) {
    138                                 result = 0;
    139                         } else {
    140                                 result = 1;
    141                         }
    142                 } else {
    143                         result = objectCast( dest, env, indexer );
    144                 }
    145         }
    146 
    147         void PtrsCastable_old::postvisit( const TraitInstType * ) {}
    148 
    149         void PtrsCastable_old::postvisit( const TypeInstType *inst ) {
    150                 //result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;
    151                 result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;
    152         }
    153 
    154         void PtrsCastable_old::postvisit( const TupleType * ) {
    155                 result = objectCast( dest, env, indexer );
    156         }
    157 
    158         void PtrsCastable_old::postvisit( const VarArgsType * ) {
    159                 result = objectCast( dest, env, indexer );
    160         }
    161 
    162         void PtrsCastable_old::postvisit( const ZeroType * ) {
    163                 result = objectCast( dest, env, indexer );
    164         }
    165 
    166         void PtrsCastable_old::postvisit( const OneType * ) {
    167                 result = objectCast( dest, env, indexer );
    168         }
    16925
    17026namespace {
  • src/ResolvExpr/RenameVars.cc

    r0030b508 rfc12f05  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
    23 #include "Common/PassVisitor.h"
    2423#include "Common/ScopedMap.h"
    2524#include "Common/SemanticError.h"  // for SemanticError
    2625#include "RenameVars.h"
    27 #include "SynTree/Declaration.h"   // for DeclarationWithType, TypeDecl, Dec...
    28 #include "SynTree/Expression.h"    // for Expression
    29 #include "SynTree/Type.h"          // for Type, TypeInstType, TraitInstType
    30 #include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
    3126
    3227#include "AST/Copy.hpp"
     
    4944                }
    5045
    51                 void rename( TypeInstType * type ) {
    52                         auto it = nameMap.find( type->name );
    53                         if ( it != nameMap.end() ) {
    54                                 type->name = it->second;
    55                         }
    56                 }
    57 
    5846                void nextUsage() {
    5947                        ++next_usage_id;
    60                 }
    61 
    62                 void openLevel( Type * type ) {
    63                         if ( ! type->forall.empty() ) {
    64                                 nameMap.beginScope();
    65                                 // renames all "forall" type names to `_${level}_${name}'
    66                                 for ( auto td : type->forall ) {
    67                                         std::ostringstream output;
    68                                         output << "_" << resetCount << "_" << level << "_" << td->name;
    69                                         std::string newname( output.str() );
    70                                         nameMap[ td->get_name() ] = newname;
    71                                         td->name = newname;
    72                                         // ditto for assertion names, the next level in
    73                                         level++;
    74                                 }
    75                         }
    76                 }
    77 
    78                 void closeLevel( Type * type ) {
    79                         if ( !type->forall.empty() ) {
    80                                 nameMap.endScope();
    81                         }
    8248                }
    8349
     
    135101        RenamingData renaming;
    136102
    137         struct RenameVars_old {
    138                 void previsit( TypeInstType * instType ) {
    139                         renaming.openLevel( (Type*)instType );
    140                         renaming.rename( instType );
    141                 }
    142                 void previsit( Type * type ) {
    143                         renaming.openLevel( type );
    144                 }
    145                 void postvisit( Type * type ) {
    146                         renaming.closeLevel( type );
    147                 }
    148         };
    149 
    150103        struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
    151104                RenameMode mode;
     
    178131} // namespace
    179132
    180 void renameTyVars( Type * t ) {
    181         PassVisitor<RenameVars_old> renamer;
    182         t->accept( renamer );
    183 }
    184 
    185133const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
    186134        ast::Pass<RenameVars_new> renamer;
  • src/ResolvExpr/RenameVars.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include <list>               // for list
    19 #include <map>                // for map
    20 #include <string>             // for string
    21 
    22 #include "SynTree/SynTree.h"  // for Visitor Nodes
    23 #include "SynTree/Visitor.h"  // for Visitor
    24 
    2518namespace ast {
    2619        class Type;
     
    2821
    2922namespace ResolvExpr {
    30         /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
    31         void renameTyVars( Type * );
    32 
    3323        enum RenameMode {
    3424                GEN_USAGE, // for type in VariableExpr
  • src/ResolvExpr/ResolveTypeof.cc

    r0030b508 rfc12f05  
    2424#include "AST/Type.hpp"
    2525#include "AST/TypeEnvironment.hpp"
    26 #include "Common/PassVisitor.h"   // for PassVisitor
    2726#include "Common/utility.h"       // for copy
    2827#include "InitTweak/InitTweak.h"  // for isConstExpr
     
    3029#include "Resolver.h"  // for resolveInVoidContext
    3130#include "SymTab/Mangler.h"
    32 #include "SynTree/Expression.h"  // for Expression
    33 #include "SynTree/Mutator.h"     // for Mutator
    34 #include "SynTree/Type.h"        // for TypeofType, Type
    35 
    36 namespace SymTab {
    37 class Indexer;
    38 }  // namespace SymTab
    3931
    4032namespace ResolvExpr {
    41 namespace {
    42 #if 0
    43                 void
    44                 printAlts( const AltList &list, std::ostream &os, int indent = 0 )
    45                 {
    46                         for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
    47                                 i->print( os, indent );
    48                                 os << std::endl;
    49                         }
    50                 }
    51 #endif
    52         }
    53 
    54 class ResolveTypeof_old : public WithShortCircuiting {
    55    public:
    56                 ResolveTypeof_old( const SymTab::Indexer &indexer ) : indexer( indexer ) {}
    57                 void premutate( TypeofType *typeofType );
    58                 Type * postmutate( TypeofType *typeofType );
    59 
    60    private:
    61     const SymTab::Indexer &indexer;
    62 };
    63 
    64         Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {
    65                 PassVisitor<ResolveTypeof_old> mutator( indexer );
    66                 return type->acceptMutator( mutator );
    67         }
    68 
    69         void ResolveTypeof_old::premutate( TypeofType * ) {
    70                 visit_children = false;
    71         }
    72 
    73     Type * ResolveTypeof_old::postmutate( TypeofType *typeofType ) {
    74 #if 0
    75                 std::cerr << "resolving typeof: ";
    76                 typeofType->print( std::cerr );
    77                 std::cerr << std::endl;
    78 #endif
    79     // pass on null expression
    80                 if ( ! typeofType->expr ) return typeofType;
    81 
    82     bool isBasetypeof = typeofType->is_basetypeof;
    83     auto oldQuals = typeofType->get_qualifiers().val;
    84 
    85     Type* newType;
    86                 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(typeofType->expr) ) {
    87         // typeof wrapping type
    88         newType = tyExpr->type;
    89         tyExpr->type = nullptr;
    90         delete tyExpr;
    91     } else {
    92         // typeof wrapping expression
    93                         Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer );
    94                         assert( newExpr->result && ! newExpr->result->isVoid() );
    95         newType = newExpr->result;
    96         newExpr->result = nullptr;
    97         delete typeofType;
    98         delete newExpr;
    99     }
    100 
    101     // clear qualifiers for base, combine with typeoftype quals in any case
    102     if ( isBasetypeof ) {
    103                         // replace basetypeof(<enum>) by int
    104                         if ( dynamic_cast<EnumInstType*>(newType) ) {
    105                                 Type* newerType =
    106                                         new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
    107                                         newType->attributes };
    108                                 delete newType;
    109                                 newType = newerType;
    110                         }
    111                         newType->get_qualifiers().val
    112                                 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
    113                 } else {
    114         newType->get_qualifiers().val |= oldQuals;
    115     }
    116 
    117     return newType;
    118 }
    11933
    12034namespace {
  • src/ResolvExpr/Resolver.cc

    r0030b508 rfc12f05  
    1919#include <vector>                        // for vector
    2020
    21 #include "Alternative.h"                 // for Alternative, AltList
    22 #include "AlternativeFinder.h"           // for AlternativeFinder, resolveIn...
    2321#include "Candidate.hpp"
    2422#include "CandidateFinder.hpp"
     
    4038#include "Common/Eval.h"                 // for eval
    4139#include "Common/Iterate.hpp"            // for group_iterate
    42 #include "Common/PassVisitor.h"          // for PassVisitor
    4340#include "Common/SemanticError.h"        // for SemanticError
    4441#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    4542#include "Common/ToString.hpp"           // for toCString
     43#include "Common/UniqueName.h"           // for UniqueName
    4644#include "InitTweak/GenInit.h"
    4745#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
    48 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    49 #include "SymTab/Autogen.h"              // for SizeType
    50 #include "SymTab/Indexer.h"              // for Indexer
    5146#include "SymTab/Mangler.h"              // for Mangler
    52 #include "SynTree/Declaration.h"         // for ObjectDecl, TypeDecl, Declar...
    53 #include "SynTree/Expression.h"          // for Expression, CastExpr, InitExpr
    54 #include "SynTree/Initializer.h"         // for ConstructorInit, SingleInit
    55 #include "SynTree/Statement.h"           // for ForStmt, Statement, BranchStmt
    56 #include "SynTree/Type.h"                // for Type, BasicType, PointerType
    57 #include "SynTree/TypeSubstitution.h"    // for TypeSubstitution
    58 #include "SynTree/Visitor.h"             // for acceptAll, maybeAccept
    5947#include "Tuples/Tuples.h"
    6048#include "Validate/FindSpecialDecls.h"   // for SizeType
     
    6351
    6452namespace ResolvExpr {
    65         struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {
    66                 Resolver_old() {}
    67                 Resolver_old( const SymTab::Indexer & other ) {
    68                         indexer = other;
    69                 }
    70 
    71                 void previsit( FunctionDecl * functionDecl );
    72                 void postvisit( FunctionDecl * functionDecl );
    73                 void previsit( ObjectDecl * objectDecll );
    74                 void previsit( EnumDecl * enumDecl );
    75                 void previsit( StaticAssertDecl * assertDecl );
    76 
    77                 void previsit( ArrayType * at );
    78                 void previsit( PointerType * at );
    79 
    80                 void previsit( ExprStmt * exprStmt );
    81                 void previsit( AsmExpr * asmExpr );
    82                 void previsit( AsmStmt * asmStmt );
    83                 void previsit( IfStmt * ifStmt );
    84                 void previsit( WhileDoStmt * whileDoStmt );
    85                 void previsit( ForStmt * forStmt );
    86                 void previsit( SwitchStmt * switchStmt );
    87                 void previsit( CaseStmt * caseStmt );
    88                 void previsit( BranchStmt * branchStmt );
    89                 void previsit( ReturnStmt * returnStmt );
    90                 void previsit( ThrowStmt * throwStmt );
    91                 void previsit( CatchStmt * catchStmt );
    92                 void postvisit( CatchStmt * catchStmt );
    93                 void previsit( WaitForStmt * stmt );
    94 
    95                 void previsit( SingleInit * singleInit );
    96                 void previsit( ListInit * listInit );
    97                 void previsit( ConstructorInit * ctorInit );
    98           private:
    99                 typedef std::list< Initializer * >::iterator InitIterator;
    100 
    101                 template< typename PtrType >
    102                 void handlePtrType( PtrType * type );
    103 
    104                 void fallbackInit( ConstructorInit * ctorInit );
    105 
    106                 Type * functionReturn = nullptr;
    107                 CurrentObject currentObject = nullptr;
    108                 bool inEnumDecl = false;
    109         };
    110 
    111         struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {
    112                 void previsit( FunctionDecl * );
    113                 void previsit( WithStmt * );
    114 
    115                 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );
    116         };
    117 
    118         void resolve( std::list< Declaration * > translationUnit ) {
    119                 PassVisitor<Resolver_old> resolver;
    120                 acceptAll( translationUnit, resolver );
    121         }
    122 
    123         void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {
    124                 PassVisitor<Resolver_old> resolver( indexer );
    125                 maybeAccept( decl, resolver );
    126         }
    127 
    128         namespace {
    129                 struct DeleteFinder_old : public WithShortCircuiting    {
    130                         DeletedExpr * delExpr = nullptr;
    131                         void previsit( DeletedExpr * expr ) {
    132                                 if ( delExpr ) visit_children = false;
    133                                 else delExpr = expr;
    134                         }
    135 
    136                         void previsit( Expression * ) {
    137                                 if ( delExpr ) visit_children = false;
    138                         }
    139                 };
    140         }
    141 
    142         DeletedExpr * findDeletedExpr( Expression * expr ) {
    143                 PassVisitor<DeleteFinder_old> finder;
    144                 expr->accept( finder );
    145                 return finder.pass.delExpr;
    146         }
    147 
    148         namespace {
    149                 struct StripCasts_old {
    150                         Expression * postmutate( CastExpr * castExpr ) {
    151                                 if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {
    152                                         // generated cast is to the same type as its argument, so it's unnecessary -- remove it
    153                                         Expression * expr = castExpr->arg;
    154                                         castExpr->arg = nullptr;
    155                                         std::swap( expr->env, castExpr->env );
    156                                         return expr;
    157                                 }
    158                                 return castExpr;
    159                         }
    160 
    161                         static void strip( Expression *& expr ) {
    162                                 PassVisitor<StripCasts_old> stripper;
    163                                 expr = expr->acceptMutator( stripper );
    164                         }
    165                 };
    166 
    167                 void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {
    168                         expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;
    169                         env.makeSubstitution( *expr->env );
    170                         StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression
    171                 }
    172 
    173                 void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {
    174                         if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    175                                 if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {
    176                                         // cast is to the same type as its argument, so it's unnecessary -- remove it
    177                                         expr = castExpr->arg;
    178                                         castExpr->arg = nullptr;
    179                                         std::swap( expr->env, castExpr->env );
    180                                         delete castExpr;
    181                                 }
    182                         }
    183                 }
    184         } // namespace
    185 
    186         namespace {
    187                 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {
    188                         assertf( untyped, "expected a non-null expression." );
    189 
    190                         // xxx - this isn't thread-safe, but should work until we parallelize the resolver
    191                         static unsigned recursion_level = 0;
    192 
    193                         ++recursion_level;
    194                         TypeEnvironment env;
    195                         AlternativeFinder finder( indexer, env );
    196                         finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
    197                         --recursion_level;
    198 
    199                         #if 0
    200                         if ( finder.get_alternatives().size() != 1 ) {
    201                                 std::cerr << "untyped expr is ";
    202                                 untyped->print( std::cerr );
    203                                 std::cerr << std::endl << "alternatives are:";
    204                                 for ( const Alternative & alt : finder.get_alternatives() ) {
    205                                         alt.print( std::cerr );
    206                                 } // for
    207                         } // if
    208                         #endif
    209 
    210                         // produce filtered list of alternatives
    211                         AltList candidates;
    212                         for ( Alternative & alt : finder.get_alternatives() ) {
    213                                 if ( pred( alt ) ) {
    214                                         candidates.push_back( std::move( alt ) );
    215                                 }
    216                         }
    217 
    218                         // produce invalid error if no candidates
    219                         if ( candidates.empty() ) {
    220                                 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
    221                         }
    222 
    223                         // search for cheapest candidate
    224                         AltList winners;
    225                         bool seen_undeleted = false;
    226                         for ( unsigned i = 0; i < candidates.size(); ++i ) {
    227                                 int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );
    228 
    229                                 if ( c > 0 ) continue; // skip more expensive than winner
    230 
    231                                 if ( c < 0 ) {
    232                                         // reset on new cheapest
    233                                         seen_undeleted = ! findDeletedExpr( candidates[i].expr );
    234                                         winners.clear();
    235                                 } else /* if ( c == 0 ) */ {
    236                                         if ( findDeletedExpr( candidates[i].expr ) ) {
    237                                                 // skip deleted expression if already seen one equivalent-cost not
    238                                                 if ( seen_undeleted ) continue;
    239                                         } else if ( ! seen_undeleted ) {
    240                                                 // replace list of equivalent-cost deleted expressions with one non-deleted
    241                                                 winners.clear();
    242                                                 seen_undeleted = true;
    243                                         }
    244                                 }
    245 
    246                                 winners.emplace_back( std::move( candidates[i] ) );
    247                         }
    248 
    249                         // promote alternative.cvtCost to .cost
    250                         // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost
    251                         for ( Alternative& winner : winners ) {
    252                                 winner.cost = winner.cvtCost;
    253                         }
    254 
    255                         // produce ambiguous errors, if applicable
    256                         if ( winners.size() != 1 ) {
    257                                 std::ostringstream stream;
    258                                 stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
    259                                 untyped->print( stream );
    260                                 stream << " Alternatives are:\n";
    261                                 printAlts( winners, stream, 1 );
    262                                 SemanticError( untyped->location, stream.str() );
    263                         }
    264 
    265                         // single selected choice
    266                         Alternative& choice = winners.front();
    267 
    268                         // fail on only expression deleted
    269                         if ( ! seen_undeleted ) {
    270                                 SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );
    271                         }
    272 
    273                         // xxx - check for ambiguous expressions
    274 
    275                         // output selected choice
    276                         alt = std::move( choice );
    277                 }
    278 
    279                 /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
    280                 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {
    281                         if ( ! untyped ) return;
    282                         Alternative choice;
    283                         findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );
    284                         finishExpr( choice.expr, choice.env, untyped->env );
    285                         delete untyped;
    286                         untyped = choice.expr;
    287                         choice.expr = nullptr;
    288                 }
    289 
    290                 bool standardAlternativeFilter( const Alternative & ) {
    291                         // currently don't need to filter, under normal circumstances.
    292                         // in the future, this may be useful for removing deleted expressions
    293                         return true;
    294                 }
    295         } // namespace
    296 
    297         // used in resolveTypeof
    298         Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {
    299                 TypeEnvironment env;
    300                 return resolveInVoidContext( expr, indexer, env );
    301         }
    302 
    303         Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {
    304                 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
    305                 // interpretations, an exception has already been thrown.
    306                 assertf( expr, "expected a non-null expression." );
    307 
    308                 CastExpr * untyped = new CastExpr( expr ); // cast to void
    309                 untyped->location = expr->location;
    310 
    311                 // set up and resolve expression cast to void
    312                 Alternative choice;
    313                 findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
    314                 CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
    315                 assert( castExpr );
    316                 env = std::move( choice.env );
    317 
    318                 // clean up resolved expression
    319                 Expression * ret = castExpr->arg;
    320                 castExpr->arg = nullptr;
    321 
    322                 // unlink the arg so that it isn't deleted twice at the end of the program
    323                 untyped->arg = nullptr;
    324                 return ret;
    325         }
    326 
    327         void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    328                 resetTyVarRenaming();
    329                 TypeEnvironment env;
    330                 Expression * newExpr = resolveInVoidContext( untyped, indexer, env );
    331                 finishExpr( newExpr, env, untyped->env );
    332                 delete untyped;
    333                 untyped = newExpr;
    334         }
    335 
    336         void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    337                 findKindExpression( untyped, indexer, "", standardAlternativeFilter );
    338         }
    339 
    340         void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer ) {
    341                 assert( untyped && type );
    342                 // transfer location to generated cast for error purposes
    343                 CodeLocation location = untyped->location;
    344                 untyped = new CastExpr( untyped, type );
    345                 untyped->location = location;
    346                 findSingleExpression( untyped, indexer );
    347                 removeExtraneousCast( untyped, indexer );
    348         }
    349 
    350         namespace {
    351                 bool isIntegralType( const Alternative & alt ) {
    352                         Type * type = alt.expr->result;
    353                         if ( dynamic_cast< EnumInstType * >( type ) ) {
    354                                 return true;
    355                         } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {
    356                                 return bt->isInteger();
    357                         } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {
    358                                 return true;
    359                         } else {
    360                                 return false;
    361                         } // if
    362                 }
    363 
    364                 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    365                         findKindExpression( untyped, indexer, "condition", isIntegralType );
    366                 }
    367         }
    368 
    369 
    370         bool isStructOrUnion( const Alternative & alt ) {
    371                 Type * t = alt.expr->result->stripReferences();
    372                 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );
    373         }
    374 
    375         void resolveWithExprs( std::list< Declaration * > & translationUnit ) {
    376                 PassVisitor<ResolveWithExprs> resolver;
    377                 acceptAll( translationUnit, resolver );
    378         }
    379 
    380         void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {
    381                 for ( Expression *& expr : withExprs )  {
    382                         // only struct- and union-typed expressions are viable candidates
    383                         findKindExpression( expr, indexer, "with statement", isStructOrUnion );
    384 
    385                         // if with expression might be impure, create a temporary so that it is evaluated once
    386                         if ( Tuples::maybeImpure( expr ) ) {
    387                                 static UniqueName tmpNamer( "_with_tmp_" );
    388                                 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );
    389                                 expr = new VariableExpr( tmp );
    390                                 newStmts.push_back( new DeclStmt( tmp ) );
    391                                 if ( InitTweak::isConstructable( tmp->type ) ) {
    392                                         // generate ctor/dtor and resolve them
    393                                         tmp->init = InitTweak::genCtorInit( tmp );
    394                                         tmp->accept( *visitor );
    395                                 }
    396                         }
    397                 }
    398         }
    399 
    400         void ResolveWithExprs::previsit( WithStmt * withStmt ) {
    401                 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );
    402         }
    403 
    404         void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {
    405                 {
    406                         // resolve with-exprs with parameters in scope and add any newly generated declarations to the
    407                         // front of the function body.
    408                         auto guard = makeFuncGuard( [this]() { indexer.enterScope(); }, [this](){ indexer.leaveScope(); } );
    409                         indexer.addFunctionType( functionDecl->type );
    410                         std::list< Statement * > newStmts;
    411                         resolveWithExprs( functionDecl->withExprs, newStmts );
    412                         if ( functionDecl->statements ) {
    413                                 functionDecl->statements->kids.splice( functionDecl->statements->kids.begin(), newStmts );
    414                         } else {
    415                                 assertf( functionDecl->withExprs.empty() && newStmts.empty(), "Function %s without a body has with-clause and/or generated with declarations.", functionDecl->name.c_str() );
    416                         }
    417                 }
    418         }
    419 
    420         void Resolver_old::previsit( ObjectDecl * objectDecl ) {
    421                 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that
    422                 // class-variable initContext is changed multiple time because the LHS is analysed twice.
    423                 // The second analysis changes initContext because of a function type can contain object
    424                 // declarations in the return and parameter types. So each value of initContext is
    425                 // retained, so the type on the first analysis is preserved and used for selecting the RHS.
    426                 GuardValue( currentObject );
    427                 currentObject = CurrentObject( objectDecl->get_type() );
    428                 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {
    429                         // enumerator initializers should not use the enum type to initialize, since
    430                         // the enum type is still incomplete at this point. Use signed int instead.
    431                         // TODO: BasicType::SignedInt may not longer be true
    432                         currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    433                 }
    434         }
    435 
    436         template< typename PtrType >
    437         void Resolver_old::handlePtrType( PtrType * type ) {
    438                 if ( type->get_dimension() ) {
    439                         findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
    440                 }
    441         }
    442 
    443         void Resolver_old::previsit( ArrayType * at ) {
    444                 handlePtrType( at );
    445         }
    446 
    447         void Resolver_old::previsit( PointerType * pt ) {
    448                 handlePtrType( pt );
    449         }
    450 
    451         void Resolver_old::previsit( FunctionDecl * functionDecl ) {
    452 #if 0
    453                 std::cerr << "resolver visiting functiondecl ";
    454                 functionDecl->print( std::cerr );
    455                 std::cerr << std::endl;
    456 #endif
    457                 GuardValue( functionReturn );
    458                 functionReturn = ResolvExpr::extractResultType( functionDecl->type );
    459         }
    460 
    461         void Resolver_old::postvisit( FunctionDecl * functionDecl ) {
    462                 // default value expressions have an environment which shouldn't be there and trips up
    463                 // later passes.
    464                 // xxx - it might be necessary to somehow keep the information from this environment, but I
    465                 // can't currently see how it's useful.
    466                 for ( Declaration * d : functionDecl->type->parameters ) {
    467                         if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {
    468                                 if ( SingleInit * init = dynamic_cast< SingleInit * >( obj->init ) ) {
    469                                         delete init->value->env;
    470                                         init->value->env = nullptr;
    471                                 }
    472                         }
    473                 }
    474         }
    475 
    476         void Resolver_old::previsit( EnumDecl * ) {
    477                 // in case we decide to allow nested enums
    478                 GuardValue( inEnumDecl );
    479                 inEnumDecl = true;
    480         }
    481 
    482         void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {
    483                 findIntegralExpression( assertDecl->condition, indexer );
    484         }
    485 
    486         void Resolver_old::previsit( ExprStmt * exprStmt ) {
    487                 visit_children = false;
    488                 assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );
    489                 findVoidExpression( exprStmt->expr, indexer );
    490         }
    491 
    492         void Resolver_old::previsit( AsmExpr * asmExpr ) {
    493                 visit_children = false;
    494                 findVoidExpression( asmExpr->operand, indexer );
    495         }
    496 
    497         void Resolver_old::previsit( AsmStmt * asmStmt ) {
    498                 visit_children = false;
    499                 acceptAll( asmStmt->get_input(), *visitor );
    500                 acceptAll( asmStmt->get_output(), *visitor );
    501         }
    502 
    503         void Resolver_old::previsit( IfStmt * ifStmt ) {
    504                 findIntegralExpression( ifStmt->condition, indexer );
    505         }
    506 
    507         void Resolver_old::previsit( WhileDoStmt * whileDoStmt ) {
    508                 findIntegralExpression( whileDoStmt->condition, indexer );
    509         }
    510 
    511         void Resolver_old::previsit( ForStmt * forStmt ) {
    512                 if ( forStmt->condition ) {
    513                         findIntegralExpression( forStmt->condition, indexer );
    514                 } // if
    515 
    516                 if ( forStmt->increment ) {
    517                         findVoidExpression( forStmt->increment, indexer );
    518                 } // if
    519         }
    520 
    521         void Resolver_old::previsit( SwitchStmt * switchStmt ) {
    522                 GuardValue( currentObject );
    523                 findIntegralExpression( switchStmt->condition, indexer );
    524 
    525                 currentObject = CurrentObject( switchStmt->condition->result );
    526         }
    527 
    528         void Resolver_old::previsit( CaseStmt * caseStmt ) {
    529                 if ( caseStmt->condition ) {
    530                         std::list< InitAlternative > initAlts = currentObject.getOptions();
    531                         assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral expression." );
    532                         // must remove cast from case statement because RangeExpr cannot be cast.
    533                         Expression * newExpr = new CastExpr( caseStmt->condition, initAlts.front().type->clone() );
    534                         findSingleExpression( newExpr, indexer );
    535                         // case condition cannot have a cast in C, so it must be removed, regardless of whether it performs a conversion.
    536                         // Ideally we would perform the conversion internally here.
    537                         if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( newExpr ) ) {
    538                                 newExpr = castExpr->arg;
    539                                 castExpr->arg = nullptr;
    540                                 std::swap( newExpr->env, castExpr->env );
    541                                 delete castExpr;
    542                         }
    543                         caseStmt->condition = newExpr;
    544                 }
    545         }
    546 
    547         void Resolver_old::previsit( BranchStmt * branchStmt ) {
    548                 visit_children = false;
    549                 // must resolve the argument for a computed goto
    550                 if ( branchStmt->get_type() == BranchStmt::Goto ) { // check for computed goto statement
    551                         if ( branchStmt->computedTarget ) {
    552                                 // computed goto argument is void *
    553                                 findSingleExpression( branchStmt->computedTarget, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), indexer );
    554                         } // if
    555                 } // if
    556         }
    557 
    558         void Resolver_old::previsit( ReturnStmt * returnStmt ) {
    559                 visit_children = false;
    560                 if ( returnStmt->expr ) {
    561                         findSingleExpression( returnStmt->expr, functionReturn->clone(), indexer );
    562                 } // if
    563         }
    564 
    565         void Resolver_old::previsit( ThrowStmt * throwStmt ) {
    566                 visit_children = false;
    567                 // TODO: Replace *exception type with &exception type.
    568                 if ( throwStmt->get_expr() ) {
    569                         const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );
    570                         assert( exception_decl );
    571                         Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
    572                         findSingleExpression( throwStmt->expr, exceptType, indexer );
    573                 }
    574         }
    575 
    576         void Resolver_old::previsit( CatchStmt * catchStmt ) {
    577                 // Until we are very sure this invarent (ifs that move between passes have then)
    578                 // holds, check it. This allows a check for when to decode the mangling.
    579                 if ( IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body ) ) {
    580                         assert( ifStmt->then );
    581                 }
    582                 // Encode the catchStmt so the condition can see the declaration.
    583                 if ( catchStmt->cond ) {
    584                         IfStmt * ifStmt = new IfStmt( catchStmt->cond, nullptr, catchStmt->body );
    585                         catchStmt->cond = nullptr;
    586                         catchStmt->body = ifStmt;
    587                 }
    588         }
    589 
    590         void Resolver_old::postvisit( CatchStmt * catchStmt ) {
    591                 // Decode the catchStmt so everything is stored properly.
    592                 IfStmt * ifStmt = dynamic_cast<IfStmt *>( catchStmt->body );
    593                 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
    594                         assert( ifStmt->condition );
    595                         assert( ifStmt->else_ );
    596                         catchStmt->cond = ifStmt->condition;
    597                         catchStmt->body = ifStmt->else_;
    598                         ifStmt->condition = nullptr;
    599                         ifStmt->else_ = nullptr;
    600                         delete ifStmt;
    601                 }
    602         }
    603 
    60453        template< typename iterator_t >
    60554        inline bool advance_to_mutex( iterator_t & it, const iterator_t & end ) {
     
    61059                return it != end;
    61160        }
    612 
    613         void Resolver_old::previsit( WaitForStmt * stmt ) {
    614                 visit_children = false;
    615 
    616                 // Resolve all clauses first
    617                 for( auto& clause : stmt->clauses ) {
    618 
    619                         TypeEnvironment env;
    620                         AlternativeFinder funcFinder( indexer, env );
    621 
    622                         // Find all alternatives for a function in canonical form
    623                         funcFinder.findWithAdjustment( clause.target.function );
    624 
    625                         if ( funcFinder.get_alternatives().empty() ) {
    626                                 stringstream ss;
    627                                 ss << "Use of undeclared indentifier '";
    628                                 ss << strict_dynamic_cast<NameExpr*>( clause.target.function )->name;
    629                                 ss << "' in call to waitfor";
    630                                 SemanticError( stmt->location, ss.str() );
    631                         }
    632 
    633                         if(clause.target.arguments.empty()) {
    634                                 SemanticError( stmt->location, "Waitfor clause must have at least one mutex parameter");
    635                         }
    636 
    637                         // Find all alternatives for all arguments in canonical form
    638                         std::vector< AlternativeFinder > argAlternatives;
    639                         funcFinder.findSubExprs( clause.target.arguments.begin(), clause.target.arguments.end(), back_inserter( argAlternatives ) );
    640 
    641                         // List all combinations of arguments
    642                         std::vector< AltList > possibilities;
    643                         combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
    644 
    645                         AltList                func_candidates;
    646                         std::vector< AltList > args_candidates;
    647 
    648                         // For every possible function :
    649                         //      try matching the arguments to the parameters
    650                         //      not the other way around because we have more arguments than parameters
    651                         SemanticErrorException errors;
    652                         for ( Alternative & func : funcFinder.get_alternatives() ) {
    653                                 try {
    654                                         PointerType * pointer = dynamic_cast< PointerType* >( func.expr->get_result()->stripReferences() );
    655                                         if( !pointer ) {
    656                                                 SemanticError( func.expr->get_result(), "candidate not viable: not a pointer type\n" );
    657                                         }
    658 
    659                                         FunctionType * function = dynamic_cast< FunctionType* >( pointer->get_base() );
    660                                         if( !function ) {
    661                                                 SemanticError( pointer->get_base(), "candidate not viable: not a function type\n" );
    662                                         }
    663 
    664 
    665                                         {
    666                                                 auto param     = function->parameters.begin();
    667                                                 auto param_end = function->parameters.end();
    668 
    669                                                 if( !advance_to_mutex( param, param_end ) ) {
    670                                                         SemanticError(function, "candidate function not viable: no mutex parameters\n");
    671                                                 }
    672                                         }
    673 
    674                                         Alternative newFunc( func );
    675                                         // Strip reference from function
    676                                         referenceToRvalueConversion( newFunc.expr, newFunc.cost );
    677 
    678                                         // For all the set of arguments we have try to match it with the parameter of the current function alternative
    679                                         for ( auto & argsList : possibilities ) {
    680 
    681                                                 try {
    682                                                         // Declare data structures need for resolution
    683                                                         OpenVarSet openVars;
    684                                                         AssertionSet resultNeed, resultHave;
    685                                                         TypeEnvironment resultEnv( func.env );
    686                                                         makeUnifiableVars( function, openVars, resultNeed );
    687                                                         // add all type variables as open variables now so that those not used in the parameter
    688                                                         // list are still considered open.
    689                                                         resultEnv.add( function->forall );
    690 
    691                                                         // Load type variables from arguemnts into one shared space
    692                                                         simpleCombineEnvironments( argsList.begin(), argsList.end(), resultEnv );
    693 
    694                                                         // Make sure we don't widen any existing bindings
    695                                                         resultEnv.forbidWidening();
    696 
    697                                                         // Find any unbound type variables
    698                                                         resultEnv.extractOpenVars( openVars );
    699 
    700                                                         auto param     = function->parameters.begin();
    701                                                         auto param_end = function->parameters.end();
    702 
    703                                                         int n_mutex_param = 0;
    704 
    705                                                         // For every arguments of its set, check if it matches one of the parameter
    706                                                         // The order is important
    707                                                         for( auto & arg : argsList ) {
    708 
    709                                                                 // Ignore non-mutex arguments
    710                                                                 if( !advance_to_mutex( param, param_end ) ) {
    711                                                                         // We ran out of parameters but still have arguments
    712                                                                         // this function doesn't match
    713                                                                         SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));
    714                                                                 }
    715 
    716                                                                 n_mutex_param++;
    717 
    718                                                                 // Check if the argument matches the parameter type in the current scope
    719                                                                 if( ! unify( arg.expr->get_result(), (*param)->get_type(), resultEnv, resultNeed, resultHave, openVars, this->indexer ) ) {
    720                                                                         // Type doesn't match
    721                                                                         stringstream ss;
    722                                                                         ss << "candidate function not viable: no known convertion from '";
    723                                                                         (*param)->get_type()->print( ss );
    724                                                                         ss << "' to '";
    725                                                                         arg.expr->get_result()->print( ss );
    726                                                                         ss << "' with env '";
    727                                                                         resultEnv.print(ss);
    728                                                                         ss << "'\n";
    729                                                                         SemanticError( function, ss.str() );
    730                                                                 }
    731 
    732                                                                 param++;
    733                                                         }
    734 
    735                                                         // All arguments match !
    736 
    737                                                         // Check if parameters are missing
    738                                                         if( advance_to_mutex( param, param_end ) ) {
    739                                                                 do {
    740                                                                         n_mutex_param++;
    741                                                                         param++;
    742                                                                 } while( advance_to_mutex( param, param_end ) );
    743 
    744                                                                 // We ran out of arguments but still have parameters left
    745                                                                 // this function doesn't match
    746                                                                 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));
    747                                                         }
    748 
    749                                                         // All parameters match !
    750 
    751                                                         // Finish the expressions to tie in the proper environments
    752                                                         finishExpr( newFunc.expr, resultEnv );
    753                                                         for( Alternative & alt : argsList ) {
    754                                                                 finishExpr( alt.expr, resultEnv );
    755                                                         }
    756 
    757                                                         // This is a match store it and save it for later
    758                                                         func_candidates.push_back( newFunc );
    759                                                         args_candidates.push_back( argsList );
    760 
    761                                                 }
    762                                                 catch( SemanticErrorException & e ) {
    763                                                         errors.append( e );
    764                                                 }
    765                                         }
    766                                 }
    767                                 catch( SemanticErrorException & e ) {
    768                                         errors.append( e );
    769                                 }
    770                         }
    771 
    772                         // Make sure we got the right number of arguments
    773                         if( func_candidates.empty() )    { SemanticErrorException top( stmt->location, "No alternatives for function in call to waitfor"  ); top.append( errors ); throw top; }
    774                         if( args_candidates.empty() )    { SemanticErrorException top( stmt->location, "No alternatives for arguments in call to waitfor" ); top.append( errors ); throw top; }
    775                         if( func_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous function in call to waitfor"            ); top.append( errors ); throw top; }
    776                         if( args_candidates.size() > 1 ) { SemanticErrorException top( stmt->location, "Ambiguous arguments in call to waitfor"           ); top.append( errors ); throw top; }
    777                         // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
    778 
    779                         // Swap the results from the alternative with the unresolved values.
    780                         // Alternatives will handle deletion on destruction
    781                         std::swap( clause.target.function, func_candidates.front().expr );
    782                         for( auto arg_pair : group_iterate( clause.target.arguments, args_candidates.front() ) ) {
    783                                 std::swap ( std::get<0>( arg_pair), std::get<1>( arg_pair).expr );
    784                         }
    785 
    786                         // Resolve the conditions as if it were an IfStmt
    787                         // Resolve the statments normally
    788                         findSingleExpression( clause.condition, this->indexer );
    789                         clause.statement->accept( *visitor );
    790                 }
    791 
    792 
    793                 if( stmt->timeout.statement ) {
    794                         // Resolve the timeout as an size_t for now
    795                         // Resolve the conditions as if it were an IfStmt
    796                         // Resolve the statments normally
    797                         findSingleExpression( stmt->timeout.time, new BasicType( noQualifiers, BasicType::LongLongUnsignedInt ), this->indexer );
    798                         findSingleExpression( stmt->timeout.condition, this->indexer );
    799                         stmt->timeout.statement->accept( *visitor );
    800                 }
    801 
    802                 if( stmt->orelse.statement ) {
    803                         // Resolve the conditions as if it were an IfStmt
    804                         // Resolve the statments normally
    805                         findSingleExpression( stmt->orelse.condition, this->indexer );
    806                         stmt->orelse.statement->accept( *visitor );
    807                 }
    808         }
    809 
    810         bool isCharType( Type * t ) {
    811                 if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {
    812                         return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||
    813                                 bt->get_kind() == BasicType::UnsignedChar;
    814                 }
    815                 return false;
    816         }
    817 
    818         void Resolver_old::previsit( SingleInit * singleInit ) {
    819                 visit_children = false;
    820                 // resolve initialization using the possibilities as determined by the currentObject cursor
    821                 Expression * newExpr = new UntypedInitExpr( singleInit->value, currentObject.getOptions() );
    822                 findSingleExpression( newExpr, indexer );
    823                 InitExpr * initExpr = strict_dynamic_cast< InitExpr * >( newExpr );
    824 
    825                 // move cursor to the object that is actually initialized
    826                 currentObject.setNext( initExpr->get_designation() );
    827 
    828                 // discard InitExpr wrapper and retain relevant pieces
    829                 newExpr = initExpr->expr;
    830                 initExpr->expr = nullptr;
    831                 std::swap( initExpr->env, newExpr->env );
    832                 // InitExpr may have inferParams in the case where the expression specializes a function
    833                 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not
    834                 // sufficient.
    835                 newExpr->spliceInferParams( initExpr );
    836                 delete initExpr;
    837 
    838                 // get the actual object's type (may not exactly match what comes back from the resolver
    839                 // due to conversions)
    840                 Type * initContext = currentObject.getCurrentType();
    841 
    842                 removeExtraneousCast( newExpr, indexer );
    843 
    844                 // check if actual object's type is char[]
    845                 if ( ArrayType * at = dynamic_cast< ArrayType * >( initContext ) ) {
    846                         if ( isCharType( at->get_base() ) ) {
    847                                 // check if the resolved type is char *
    848                                 if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {
    849                                         if ( isCharType( pt->get_base() ) ) {
    850                                                 if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {
    851                                                         // strip cast if we're initializing a char[] with a char *,
    852                                                         // e.g.  char x[] = "hello";
    853                                                         newExpr = ce->get_arg();
    854                                                         ce->set_arg( nullptr );
    855                                                         std::swap( ce->env, newExpr->env );
    856                                                         delete ce;
    857                                                 }
    858                                         }
    859                                 }
    860                         }
    861                 }
    862 
    863                 // set initializer expr to resolved express
    864                 singleInit->value = newExpr;
    865 
    866                 // move cursor to next object in preparation for next initializer
    867                 currentObject.increment();
    868         }
    869 
    870         void Resolver_old::previsit( ListInit * listInit ) {
    871                 visit_children = false;
    872                 // move cursor into brace-enclosed initializer-list
    873                 currentObject.enterListInit();
    874                 // xxx - fix this so that the list isn't copied, iterator should be used to change current
    875                 // element
    876                 std::list<Designation *> newDesignations;
    877                 for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {
    878                         // iterate designations and initializers in pairs, moving the cursor to the current
    879                         // designated object and resolving the initializer against that object.
    880                         Designation * des = std::get<0>(p);
    881                         Initializer * init = std::get<1>(p);
    882                         newDesignations.push_back( currentObject.findNext( des ) );
    883                         init->accept( *visitor );
    884                 }
    885                 // set the set of 'resolved' designations and leave the brace-enclosed initializer-list
    886                 listInit->get_designations() = newDesignations; // xxx - memory management
    887                 currentObject.exitListInit();
    888 
    889                 // xxx - this part has not be folded into CurrentObject yet
    890                 // } else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {
    891                 //      Type * base = tt->get_baseType()->get_base();
    892                 //      if ( base ) {
    893                 //              // know the implementation type, so try using that as the initContext
    894                 //              ObjectDecl tmpObj( "", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, base->clone(), nullptr );
    895                 //              currentObject = &tmpObj;
    896                 //              visit( listInit );
    897                 //      } else {
    898                 //              // missing implementation type -- might be an unknown type variable, so try proceeding with the current init context
    899                 //              Parent::visit( listInit );
    900                 //      }
    901                 // } else {
    902         }
    903 
    904         // ConstructorInit - fall back on C-style initializer
    905         void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {
    906                 // could not find valid constructor, or found an intrinsic constructor
    907                 // fall back on C-style initializer
    908                 delete ctorInit->get_ctor();
    909                 ctorInit->set_ctor( nullptr );
    910                 delete ctorInit->get_dtor();
    911                 ctorInit->set_dtor( nullptr );
    912                 maybeAccept( ctorInit->get_init(), *visitor );
    913         }
    914 
    915         // needs to be callable from outside the resolver, so this is a standalone function
    916         void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {
    917                 assert( ctorInit );
    918                 PassVisitor<Resolver_old> resolver( indexer );
    919                 ctorInit->accept( resolver );
    920         }
    921 
    922         void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {
    923                 assert( stmtExpr );
    924                 PassVisitor<Resolver_old> resolver( indexer );
    925                 stmtExpr->accept( resolver );
    926                 stmtExpr->computeResult();
    927                 // xxx - aggregate the environments from all statements? Possibly in AlternativeFinder instead?
    928         }
    929 
    930         void Resolver_old::previsit( ConstructorInit * ctorInit ) {
    931                 visit_children = false;
    932                 // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit
    933                 maybeAccept( ctorInit->ctor, *visitor );
    934                 maybeAccept( ctorInit->dtor, *visitor );
    935 
    936                 // found a constructor - can get rid of C-style initializer
    937                 delete ctorInit->init;
    938                 ctorInit->init = nullptr;
    939 
    940                 // intrinsic single parameter constructors and destructors do nothing. Since this was
    941                 // implicitly generated, there's no way for it to have side effects, so get rid of it
    942                 // to clean up generated code.
    943                 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
    944                         delete ctorInit->ctor;
    945                         ctorInit->ctor = nullptr;
    946                 }
    947 
    948                 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
    949                         delete ctorInit->dtor;
    950                         ctorInit->dtor = nullptr;
    951                 }
    952 
    953                 // xxx - todo -- what about arrays?
    954                 // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
    955                 //      // can reduce the constructor down to a SingleInit using the
    956                 //      // second argument from the ctor call, since
    957                 //      delete ctorInit->get_ctor();
    958                 //      ctorInit->set_ctor( nullptr );
    959 
    960                 //      Expression * arg =
    961                 //      ctorInit->set_init( new SingleInit( arg ) );
    962                 // }
    963         }
    964 
    965         ///////////////////////////////////////////////////////////////////////////
    966         //
    967         // *** NEW RESOLVER ***
    968         //
    969         ///////////////////////////////////////////////////////////////////////////
    97061
    97162        namespace {
  • src/ResolvExpr/SatisfyAssertions.cpp

    r0030b508 rfc12f05  
    4646#include "SymTab/Mangler.h"
    4747
    48 
    49 
    5048namespace ResolvExpr {
    5149
    5250// in CandidateFinder.cpp; unique ID for assertion satisfaction
    53 extern UniqueId globalResnSlot;
     51extern ast::UniqueId globalResnSlot;
    5452
    5553namespace {
     
    298296                        if ( !expr->inferred.hasSlots() ) return expr;
    299297                        // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
    300                         std::vector<UniqueId> missingSlots;
     298                        std::vector<ast::UniqueId> missingSlots;
    301299                        // find inferred parameters for resolution slots
    302300                        ast::InferredParams * newInferred = new ast::InferredParams();
    303                         for ( UniqueId slot : expr->inferred.resnSlots() ) {
     301                        for ( ast::UniqueId slot : expr->inferred.resnSlots() ) {
    304302                                // fail if no matching assertions found
    305303                                auto it = inferred.find( slot );
  • src/ResolvExpr/SpecCost.cc

    r0030b508 rfc12f05  
    2121#include "AST/Pass.hpp"
    2222#include "AST/Type.hpp"
    23 #include "Common/PassVisitor.h"
    24 #include "SynTree/Declaration.h"
    25 #include "SynTree/Expression.h"
    26 #include "SynTree/Type.h"
    2723
    2824namespace ResolvExpr {
    29 
    30         /// Counts specializations in a type
    31         class CountSpecs : public WithShortCircuiting, public WithVisitorRef<CountSpecs> {
    32                 int count = -1;  ///< specialization count (-1 for none)
    33 
    34         public:
    35                 int get_count() const { return count >= 0 ? count : 0; }
    36 
    37                 // mark specialization of base type
    38                 void postvisit(PointerType*) { if ( count >= 0 ) ++count; }
    39 
    40                 // mark specialization of base type
    41                 void postvisit(ArrayType*) { if ( count >= 0 ) ++count; }
    42 
    43                 // mark specialization of base type
    44                 void postvisit(ReferenceType*) { if ( count >= 0 ) ++count; }
    45 
    46                 void postvisit(StructInstType*) { if ( count >= 0 ) ++count; }
    47                 void postvisit(UnionInstType*) { if ( count >= 0 ) ++count; }
    48 
    49         private:
    50                 // takes minimum non-negative count over parameter/return list
    51                 void takeminover( int& mincount, std::list<DeclarationWithType*>& dwts ) {
    52                         for ( DeclarationWithType* dwt : dwts ) {
    53                                 count = -1;
    54                                 maybeAccept( dwt->get_type(), *visitor );
    55                                 if ( count != -1 && count < mincount ) mincount = count;
    56                         }
    57                 }
    58 
    59         public:
    60                 // take minimal specialization value over ->returnVals and ->parameters
    61                 void previsit(FunctionType* fty) {
    62                         int mincount = std::numeric_limits<int>::max();
    63                         takeminover( mincount, fty->parameters );
    64                         takeminover( mincount, fty->returnVals );
    65                         // add another level to mincount if set
    66                         count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    67                         // already visited children
    68                         visit_children = false;
    69                 }
    70 
    71         private:
    72                 // returns minimum non-negative count + 1 over type parameters (-1 if none such)
    73                 int minover( std::list<Expression*>& parms ) {
    74                         int mincount = std::numeric_limits<int>::max();
    75                         for ( Expression* parm : parms ) {
    76                                 count = -1;
    77                                 maybeAccept( parm->result, *visitor );
    78                                 if ( count != -1 && count < mincount ) mincount = count;
    79                         }
    80                         return mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    81                 }
    82 
    83         public:
    84                 // look for polymorphic parameters
    85                 void previsit(StructInstType* sty) {
    86                         count = minover( sty->parameters );
    87                 }
    88 
    89                 // look for polymorphic parameters
    90                 void previsit(UnionInstType* uty) {
    91                         count = minover( uty->parameters );
    92                 }
    93 
    94                 // note polymorphic type (which may be specialized)
    95                 // xxx - maybe account for open/closed type variables
    96                 void postvisit(TypeInstType*) { count = 0; }
    97 
    98                 // take minimal specialization over elements
    99                 // xxx - maybe don't increment, tuple flattening doesn't necessarily specialize
    100                 void previsit(TupleType* tty) {
    101                         int mincount = std::numeric_limits<int>::max();
    102                         for ( Type* ty : tty->types ) {
    103                                 count = -1;
    104                                 maybeAccept( ty, *visitor );
    105                                 if ( count != -1 && count < mincount ) mincount = count;
    106                         }
    107                         count = mincount < std::numeric_limits<int>::max() ? mincount + 1 : -1;
    108                         visit_children = false;
    109                 }
    110         };
    111 
    112         /// Returns the (negated) specialization cost for a given type
    113         int specCost( Type* ty ) {
    114                 PassVisitor<CountSpecs> counter;
    115                 maybeAccept( ty, *counter.pass.visitor );
    116                 return counter.pass.get_count();
    117         }
    11825
    11926namespace {
  • src/ResolvExpr/Unify.cc

    r0030b508 rfc12f05  
    3333#include "AST/TypeEnvironment.hpp"
    3434#include "Common/Eval.h"            // for eval
    35 #include "Common/PassVisitor.h"     // for PassVisitor
    3635#include "CommonType.hpp"           // for commonType
    3736#include "FindOpenVars.h"           // for findOpenVars
    3837#include "SpecCost.hpp"             // for SpecCost
    39 #include "SynTree/LinkageSpec.h"    // for C
    40 #include "SynTree/Constant.h"       // for Constant
    41 #include "SynTree/Declaration.h"    // for TypeDecl, TypeDecl::Data, Declarati...
    42 #include "SynTree/Expression.h"     // for TypeExpr, Expression, ConstantExpr
    43 #include "SynTree/Mutator.h"        // for Mutator
    44 #include "SynTree/Type.h"           // for Type, TypeInstType, FunctionType
    45 #include "SynTree/Visitor.h"        // for Visitor
    4638#include "Tuples/Tuples.h"          // for isTtype
    47 #include "TypeEnvironment.h"        // for EqvClass, AssertionSet, OpenVarSet
    4839#include "typeops.h"                // for flatten, occurs
    4940
     
    5243}
    5344
    54 namespace SymTab {
    55         class Indexer;
    56 }  // namespace SymTab
    57 
    5845// #define DEBUG
    5946
    6047namespace ResolvExpr {
    61 
    62 // Template Helpers:
    63 template< typename Iterator1, typename Iterator2 >
    64 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {
    65         for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    66                 Type *commonType = 0;
    67                 if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
    68                         return false;
    69                 } // if
    70                 commonTypes.push_back( commonType );
    71         } // for
    72         return ( list1Begin == list1End && list2Begin == list2End );
    73 }
    74 
    75 template< typename Iterator1, typename Iterator2 >
    76 bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    77         std::list< Type* > commonTypes;
    78         if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions,  openVars, indexer, commonTypes ) ) {
    79                 deleteAll( commonTypes );
    80                 return true;
    81         } else {
    82                 return false;
    83         } // if
    84 }
    85 
    86         struct Unify_old : public WithShortCircuiting {
    87                 Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
    88 
    89                 bool get_result() const { return result; }
    90 
    91                 void previsit( BaseSyntaxNode * ) { visit_children = false; }
    92 
    93                 void postvisit( VoidType * voidType );
    94                 void postvisit( BasicType * basicType );
    95                 void postvisit( PointerType * pointerType );
    96                 void postvisit( ArrayType * arrayType );
    97                 void postvisit( ReferenceType * refType );
    98                 void postvisit( FunctionType * functionType );
    99                 void postvisit( StructInstType * aggregateUseType );
    100                 void postvisit( UnionInstType * aggregateUseType );
    101                 void postvisit( EnumInstType * aggregateUseType );
    102                 void postvisit( TraitInstType * aggregateUseType );
    103                 void postvisit( TypeInstType * aggregateUseType );
    104                 void postvisit( TupleType * tupleType );
    105                 void postvisit( VarArgsType * varArgsType );
    106                 void postvisit( ZeroType * zeroType );
    107                 void postvisit( OneType * oneType );
    108 
    109           private:
    110                 template< typename RefType > void handleRefType( RefType *inst, Type *other );
    111                 template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
    112 
    113                 bool result;
    114                 Type *type2;                            // inherited
    115                 TypeEnvironment &env;
    116                 AssertionSet &needAssertions;
    117                 AssertionSet &haveAssertions;
    118                 const OpenVarSet &openVars;
    119                 WidenMode widen;
    120                 const SymTab::Indexer &indexer;
    121         };
    122 
    123         /// Attempts an inexact unification of type1 and type2.
    124         /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)
    125         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    126         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
    127 
    128         bool unifyExact(
    129                 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
    130                 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    131                 WidenMode widen );
    132 
    133         bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    134                 TypeEnvironment newEnv;
    135                 OpenVarSet openVars, closedVars; // added closedVars
    136                 AssertionSet needAssertions, haveAssertions;
    137                 Type * newFirst = first->clone(), * newSecond = second->clone();
    138                 env.apply( newFirst );
    139                 env.apply( newSecond );
    140 
    141                 // do we need to do this? Seems like we do, types should be able to be compatible if they
    142                 // have free variables that can unify
    143                 findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false );
    144                 findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true );
    145 
    146                 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    147                 delete newFirst;
    148                 delete newSecond;
    149                 return result;
    150         }
    15148
    15249        bool typesCompatible(
     
    16562
    16663                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
    167         }
    168 
    169         bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    170                 TypeEnvironment newEnv;
    171                 OpenVarSet openVars;
    172                 AssertionSet needAssertions, haveAssertions;
    173                 Type *newFirst = first->clone(), *newSecond = second->clone();
    174                 env.apply( newFirst );
    175                 env.apply( newSecond );
    176                 newFirst->get_qualifiers() = Type::Qualifiers();
    177                 newSecond->get_qualifiers() = Type::Qualifiers();
    178 
    179                 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    180                 delete newFirst;
    181                 delete newSecond;
    182                 return result;
    18364        }
    18465
     
    21899                        subSecond,
    219100                        newEnv, need, have, open, noWiden() );
    220         }
    221 
    222         bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    223                 OpenVarSet closedVars;
    224                 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
    225                 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
    226                 Type *commonType = 0;
    227                 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {
    228                         if ( commonType ) {
    229                                 delete commonType;
    230                         } // if
    231                         return true;
    232                 } else {
    233                         return false;
    234                 } // if
    235         }
    236 
    237         bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) {
    238                 OpenVarSet closedVars;
    239                 findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
    240                 findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
    241                 return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType );
    242         }
    243 
    244         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
    245 #ifdef DEBUG
    246                 TypeEnvironment debugEnv( env );
    247 #endif
    248                 if ( type1->get_qualifiers() != type2->get_qualifiers() ) {
    249                         return false;
    250                 }
    251 
    252                 bool result;
    253                 TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 );
    254                 TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 );
    255                 OpenVarSet::const_iterator entry1, entry2;
    256                 if ( var1 ) {
    257                         entry1 = openVars.find( var1->get_name() );
    258                 } // if
    259                 if ( var2 ) {
    260                         entry2 = openVars.find( var2->get_name() );
    261                 } // if
    262                 bool isopen1 = var1 && ( entry1 != openVars.end() );
    263                 bool isopen2 = var2 && ( entry2 != openVars.end() );
    264 
    265                 if ( isopen1 && isopen2 ) {
    266                         if ( entry1->second.kind != entry2->second.kind ) {
    267                                 result = false;
    268                         } else {
    269                                 result = env.bindVarToVar(
    270                                         var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
    271                                         haveAssertions, openVars, widen, indexer );
    272                         }
    273                 } else if ( isopen1 ) {
    274                         result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );
    275                 } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?
    276                         result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );
    277                 } else {
    278                         PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );
    279                         type1->accept( comparator );
    280                         result = comparator.pass.get_result();
    281                 } // if
    282 #ifdef DEBUG
    283                 std::cerr << "============ unifyExact" << std::endl;
    284                 std::cerr << "type1 is ";
    285                 type1->print( std::cerr );
    286                 std::cerr << std::endl << "type2 is ";
    287                 type2->print( std::cerr );
    288                 std::cerr << std::endl << "openVars are ";
    289                 printOpenVarSet( openVars, std::cerr, 8 );
    290                 std::cerr << std::endl << "input env is " << std::endl;
    291                 debugEnv.print( std::cerr, 8 );
    292                 std::cerr << std::endl << "result env is " << std::endl;
    293                 env.print( std::cerr, 8 );
    294                 std::cerr << "result is " << result << std::endl;
    295 #endif
    296                 return result;
    297         }
    298 
    299         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    300                 return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    301         }
    302 
    303         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {
    304                 Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();
    305                 type1->get_qualifiers() = Type::Qualifiers();
    306                 type2->get_qualifiers() = Type::Qualifiers();
    307                 bool result;
    308 #ifdef DEBUG
    309                 std::cerr << "unifyInexact type 1 is ";
    310                 type1->print( std::cerr );
    311                 std::cerr << " type 2 is ";
    312                 type2->print( std::cerr );
    313                 std::cerr << std::endl;
    314 #endif
    315                 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {
    316 #ifdef DEBUG
    317                         std::cerr << "unifyInexact: no exact unification found" << std::endl;
    318 #endif
    319                         if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {
    320                                 common->tq = tq1.unify( tq2 );
    321 #ifdef DEBUG
    322                                 std::cerr << "unifyInexact: common type is ";
    323                                 common->print( std::cerr );
    324                                 std::cerr << std::endl;
    325 #endif
    326                                 result = true;
    327                         } else {
    328 #ifdef DEBUG
    329                                 std::cerr << "unifyInexact: no common type found" << std::endl;
    330 #endif
    331                                 result = false;
    332                         } // if
    333                 } else {
    334                         if ( tq1 != tq2 ) {
    335                                 if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {
    336                                         common = type1->clone();
    337                                         common->tq = tq1.unify( tq2 );
    338                                         result = true;
    339                                 } else {
    340                                         result = false;
    341                                 } // if
    342                         } else {
    343                                 common = type1->clone();
    344                                 common->tq = tq1.unify( tq2 );
    345                                 result = true;
    346                         } // if
    347                 } // if
    348                 type1->get_qualifiers() = tq1;
    349                 type2->get_qualifiers() = tq2;
    350                 return result;
    351         }
    352 
    353         Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )
    354                 : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {
    355         }
    356 
    357         void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {
    358                 result = dynamic_cast< VoidType* >( type2 );
    359         }
    360 
    361         void Unify_old::postvisit(BasicType *basicType) {
    362                 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
    363                         result = basicType->get_kind() == otherBasic->get_kind();
    364                 } // if
    365         }
    366 
    367         void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
    368                 AssertionSet::iterator i = assertions.find( assert );
    369                 if ( i != assertions.end() ) {
    370                         i->second.isUsed = true;
    371                 } // if
    372         }
    373 
    374         void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) {
    375                 for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
    376                         for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
    377                                 markAssertionSet( assertion1, *assert );
    378                                 markAssertionSet( assertion2, *assert );
    379                         } // for
    380                 } // for
    381         }
    382 
    383         void Unify_old::postvisit(PointerType *pointerType) {
    384                 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
    385                         result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    386                         markAssertions( haveAssertions, needAssertions, pointerType );
    387                         markAssertions( haveAssertions, needAssertions, otherPointer );
    388                 } // if
    389         }
    390 
    391         void Unify_old::postvisit(ReferenceType *refType) {
    392                 if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
    393                         result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    394                         markAssertions( haveAssertions, needAssertions, refType );
    395                         markAssertions( haveAssertions, needAssertions, otherRef );
    396                 } // if
    397         }
    398 
    399         void Unify_old::postvisit(ArrayType *arrayType) {
    400                 ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
    401                 // to unify, array types must both be VLA or both not VLA
    402                 // and must both have a dimension expression or not have a dimension
    403                 if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {
    404 
    405                         if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&
    406                                 arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {
    407                                 ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() );
    408                                 ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() );
    409                                 // see C11 Reference Manual 6.7.6.2.6
    410                                 // two array types with size specifiers that are integer constant expressions are
    411                                 // compatible if both size specifiers have the same constant value
    412                                 if ( ce1 && ce2 ) {
    413                                         Constant * c1 = ce1->get_constant();
    414                                         Constant * c2 = ce2->get_constant();
    415 
    416                                         if ( c1->get_value() != c2->get_value() ) {
    417                                                 // does not unify if the dimension is different
    418                                                 return;
    419                                         }
    420                                 }
    421                         }
    422 
    423                         result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    424                 } // if
    425         }
    426 
    427         template< typename Iterator, typename Func >
    428         std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {
    429                 std::list< Type * > types;
    430                 for ( ; begin != end; ++begin ) {
    431                         // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple
    432                         flatten( toType( *begin ), back_inserter( types ) );
    433                 }
    434                 return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );
    435         }
    436 
    437         template< typename Iterator1, typename Iterator2 >
    438         bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    439                 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };
    440                 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    441                         Type * t1 = (*list1Begin)->get_type();
    442                         Type * t2 = (*list2Begin)->get_type();
    443                         bool isTtype1 = Tuples::isTtype( t1 );
    444                         bool isTtype2 = Tuples::isTtype( t2 );
    445                         // xxx - assumes ttype must be last parameter
    446                         // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
    447                         if ( isTtype1 && ! isTtype2 ) {
    448                                 // combine all of the things in list2, then unify
    449                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    450                         } else if ( isTtype2 && ! isTtype1 ) {
    451                                 // combine all of the things in list1, then unify
    452                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    453                         } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
    454                                 return false;
    455                         } // if
    456                 } // for
    457                 // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype
    458                 if ( list1Begin != list1End ) {
    459                         // try unifying empty tuple type with ttype
    460                         Type * t1 = (*list1Begin)->get_type();
    461                         if ( Tuples::isTtype( t1 ) ) {
    462                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    463                         } else return false;
    464                 } else if ( list2Begin != list2End ) {
    465                         // try unifying empty tuple type with ttype
    466                         Type * t2 = (*list2Begin)->get_type();
    467                         if ( Tuples::isTtype( t2 ) ) {
    468                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    469                         } else return false;
    470                 } else {
    471                         return true;
    472                 } // if
    473         }
    474 
    475         /// Finds ttypes and replaces them with their expansion, if known.
    476         /// This needs to be done so that satisfying ttype assertions is easier.
    477         /// If this isn't done then argument lists can have wildly different
    478         /// size and structure, when they should be compatible.
    479         struct TtypeExpander_old : public WithShortCircuiting {
    480                 TypeEnvironment & tenv;
    481                 TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}
    482                 void premutate( TypeInstType * ) { visit_children = false; }
    483                 Type * postmutate( TypeInstType * typeInst ) {
    484                         if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {
    485                                 // expand ttype parameter into its actual type
    486                                 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {
    487                                         delete typeInst;
    488                                         return eqvClass->type->clone();
    489                                 }
    490                         }
    491                         return typeInst;
    492                 }
    493         };
    494 
    495         /// flattens a list of declarations, so that each tuple type has a single declaration.
    496         /// makes use of TtypeExpander to ensure ttypes are flat as well.
    497         void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {
    498                 dst.clear();
    499                 for ( DeclarationWithType * dcl : src ) {
    500                         PassVisitor<TtypeExpander_old> expander( env );
    501                         dcl->acceptMutator( expander );
    502                         std::list< Type * > types;
    503                         flatten( dcl->get_type(), back_inserter( types ) );
    504                         for ( Type * t : types ) {
    505                                 // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.
    506                                 // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.
    507                                 t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);
    508 
    509                                 dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );
    510                         }
    511                         delete dcl;
    512                 }
    513         }
    514 
    515         void Unify_old::postvisit(FunctionType *functionType) {
    516                 FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
    517                 if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
    518                         // flatten the parameter lists for both functions so that tuple structure
    519                         // doesn't affect unification. Must be a clone so that the types don't change.
    520                         std::unique_ptr<FunctionType> flatFunc( functionType->clone() );
    521                         std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );
    522                         flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );
    523                         flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );
    524 
    525                         // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
    526                         if (
    527                                         (flatFunc->parameters.size() == flatOther->parameters.size() &&
    528                                                 flatFunc->returnVals.size() == flatOther->returnVals.size())
    529                                         || flatFunc->isTtype()
    530                                         || flatOther->isTtype()
    531                         ) {
    532                                 if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    533                                         if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    534 
    535                                                 // the original types must be used in mark assertions, since pointer comparisons are used
    536                                                 markAssertions( haveAssertions, needAssertions, functionType );
    537                                                 markAssertions( haveAssertions, needAssertions, otherFunction );
    538 
    539                                                 result = true;
    540                                         } // if
    541                                 } // if
    542                         } // if
    543                 } // if
    544         }
    545 
    546         template< typename RefType >
    547         void Unify_old::handleRefType( RefType *inst, Type *other ) {
    548                 // check that other type is compatible and named the same
    549                 RefType *otherStruct = dynamic_cast< RefType* >( other );
    550                 result = otherStruct && inst->name == otherStruct->name;
    551         }
    552 
    553         template< typename RefType >
    554         void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {
    555                 // Check that other type is compatible and named the same
    556                 handleRefType( inst, other );
    557                 if ( ! result ) return;
    558                 // Check that parameters of types unify, if any
    559                 std::list< Expression* > params = inst->parameters;
    560                 std::list< Expression* > otherParams = ((RefType*)other)->parameters;
    561 
    562                 std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();
    563                 for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {
    564                         TypeExpr *param = dynamic_cast< TypeExpr* >(*it);
    565                         assertf(param, "Aggregate parameters should be type expressions");
    566                         TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);
    567                         assertf(otherParam, "Aggregate parameters should be type expressions");
    568 
    569                         Type* paramTy = param->get_type();
    570                         Type* otherParamTy = otherParam->get_type();
    571 
    572                         bool tupleParam = Tuples::isTtype( paramTy );
    573                         bool otherTupleParam = Tuples::isTtype( otherParamTy );
    574 
    575                         if ( tupleParam && otherTupleParam ) {
    576                                 ++it; ++jt;  // skip ttype parameters for break
    577                         } else if ( tupleParam ) {
    578                                 // bundle other parameters into tuple to match
    579                                 std::list< Type * > binderTypes;
    580 
    581                                 do {
    582                                         binderTypes.push_back( otherParam->get_type()->clone() );
    583                                         ++jt;
    584 
    585                                         if ( jt == otherParams.end() ) break;
    586 
    587                                         otherParam = dynamic_cast< TypeExpr* >(*jt);
    588                                         assertf(otherParam, "Aggregate parameters should be type expressions");
    589                                 } while (true);
    590 
    591                                 otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };
    592                                 ++it;  // skip ttype parameter for break
    593                         } else if ( otherTupleParam ) {
    594                                 // bundle parameters into tuple to match other
    595                                 std::list< Type * > binderTypes;
    596 
    597                                 do {
    598                                         binderTypes.push_back( param->get_type()->clone() );
    599                                         ++it;
    600 
    601                                         if ( it == params.end() ) break;
    602 
    603                                         param = dynamic_cast< TypeExpr* >(*it);
    604                                         assertf(param, "Aggregate parameters should be type expressions");
    605                                 } while (true);
    606 
    607                                 paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };
    608                                 ++jt;  // skip ttype parameter for break
    609                         }
    610 
    611                         if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {
    612                                 result = false;
    613                                 return;
    614                         }
    615 
    616                         // ttype parameter should be last
    617                         if ( tupleParam || otherTupleParam ) break;
    618                 }
    619                 result = ( it == params.end() && jt == otherParams.end() );
    620         }
    621 
    622         void Unify_old::postvisit(StructInstType *structInst) {
    623                 handleGenericRefType( structInst, type2 );
    624         }
    625 
    626         void Unify_old::postvisit(UnionInstType *unionInst) {
    627                 handleGenericRefType( unionInst, type2 );
    628         }
    629 
    630         void Unify_old::postvisit(EnumInstType *enumInst) {
    631                 handleRefType( enumInst, type2 );
    632         }
    633 
    634         void Unify_old::postvisit(TraitInstType *contextInst) {
    635                 handleRefType( contextInst, type2 );
    636         }
    637 
    638         void Unify_old::postvisit(TypeInstType *typeInst) {
    639                 assert( openVars.find( typeInst->get_name() ) == openVars.end() );
    640                 TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );
    641                 if ( otherInst && typeInst->get_name() == otherInst->get_name() ) {
    642                         result = true;
    643 ///   } else {
    644 ///     NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() );
    645 ///     if ( nt ) {
    646 ///       TypeDecl *type = dynamic_cast< TypeDecl* >( nt );
    647 ///       assert( type );
    648 ///       if ( type->get_base() ) {
    649 ///         result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    650 ///       }
    651 ///     }
    652                 } // if
    653         }
    654 
    655         template< typename Iterator1, typename Iterator2 >
    656         bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    657                 auto get_type = [](Type * t) { return t; };
    658                 for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    659                         Type * t1 = *list1Begin;
    660                         Type * t2 = *list2Begin;
    661                         bool isTtype1 = Tuples::isTtype( t1 );
    662                         bool isTtype2 = Tuples::isTtype( t2 );
    663                         // xxx - assumes ttype must be last parameter
    664                         // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
    665                         if ( isTtype1 && ! isTtype2 ) {
    666                                 // combine all of the things in list2, then unify
    667                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    668                         } else if ( isTtype2 && ! isTtype1 ) {
    669                                 // combine all of the things in list1, then unify
    670                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    671                         } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
    672                                 return false;
    673                         } // if
    674 
    675                 } // for
    676                 if ( list1Begin != list1End ) {
    677                         // try unifying empty tuple type with ttype
    678                         Type * t1 = *list1Begin;
    679                         if ( Tuples::isTtype( t1 ) ) {
    680                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    681                         } else return false;
    682                 } else if ( list2Begin != list2End ) {
    683                         // try unifying empty tuple type with ttype
    684                         Type * t2 = *list2Begin;
    685                         if ( Tuples::isTtype( t2 ) ) {
    686                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    687                         } else return false;
    688                 } else {
    689                         return true;
    690                 } // if
    691         }
    692 
    693         void Unify_old::postvisit(TupleType *tupleType) {
    694                 if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
    695                         std::unique_ptr<TupleType> flat1( tupleType->clone() );
    696                         std::unique_ptr<TupleType> flat2( otherTuple->clone() );
    697                         std::list<Type *> types1, types2;
    698 
    699                         PassVisitor<TtypeExpander_old> expander( env );
    700                         flat1->acceptMutator( expander );
    701                         flat2->acceptMutator( expander );
    702 
    703                         flatten( flat1.get(), back_inserter( types1 ) );
    704                         flatten( flat2.get(), back_inserter( types2 ) );
    705 
    706                         result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );
    707                 } // if
    708         }
    709 
    710         void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
    711                 result = dynamic_cast< VarArgsType* >( type2 );
    712         }
    713 
    714         void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
    715                 result = dynamic_cast< ZeroType* >( type2 );
    716         }
    717 
    718         void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {
    719                 result = dynamic_cast< OneType* >( type2 );
    720         }
    721 
    722         Type * extractResultType( FunctionType * function ) {
    723                 if ( function->get_returnVals().size() == 0 ) {
    724                         return new VoidType( Type::Qualifiers() );
    725                 } else if ( function->get_returnVals().size() == 1 ) {
    726                         return function->get_returnVals().front()->get_type()->clone();
    727                 } else {
    728                         std::list< Type * > types;
    729                         for ( DeclarationWithType * decl : function->get_returnVals() ) {
    730                                 types.push_back( decl->get_type()->clone() );
    731                         } // for
    732                         return new TupleType( Type::Qualifiers(), types );
    733                 }
    734101        }
    735102
  • src/ResolvExpr/Unify.h

    r0030b508 rfc12f05  
    2020#include "AST/Node.hpp"             // for ptr
    2121#include "AST/TypeEnvironment.hpp"  // for TypeEnvironment, AssertionSet, OpenVarSet
    22 #include "Common/utility.h"       // for deleteAll
    23 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Data
    24 #include "TypeEnvironment.h"      // for AssertionSet, OpenVarSet
    2522#include "WidenMode.h"              // for WidenMode
    26 
    27 class Type;
    28 class TypeInstType;
    29 namespace SymTab {
    30         class Indexer;
    31 }
    3223
    3324namespace ast {
     
    3728
    3829namespace ResolvExpr {
    39 
    40 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    41 bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );
    42 bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    43 bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    44 
    45 bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    46 bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
    47 
    48 inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    49         TypeEnvironment env;
    50         return typesCompatible( t1, t2, indexer, env );
    51 }
    52 
    53 inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    54         TypeEnvironment env;
    55         return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );
    56 }
    5730
    5831bool unify(
     
    8558        const ast::TypeEnvironment & env = {} );
    8659
    87 /// Creates the type represented by the list of returnVals in a FunctionType.
    88 /// The caller owns the return value.
    89 Type * extractResultType( FunctionType * functionType );
    9060/// Creates or extracts the type represented by returns in a `FunctionType`.
    9161ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
  • src/ResolvExpr/module.mk

    r0030b508 rfc12f05  
    1818      ResolvExpr/AdjustExprType.cc \
    1919      ResolvExpr/AdjustExprType.hpp \
    20       ResolvExpr/Alternative.cc \
    21       ResolvExpr/AlternativeFinder.cc \
    22       ResolvExpr/AlternativeFinder.h \
    23       ResolvExpr/Alternative.h \
    2420      ResolvExpr/Candidate.cpp \
    2521      ResolvExpr/CandidateFinder.cpp \
     
    3531      ResolvExpr/CurrentObject.cc \
    3632      ResolvExpr/CurrentObject.h \
    37       ResolvExpr/ExplodedActual.cc \
    38       ResolvExpr/ExplodedActual.h \
    3933      ResolvExpr/ExplodedArg.cpp \
    4034      ResolvExpr/ExplodedArg.hpp \
    4135      ResolvExpr/FindOpenVars.cc \
    4236      ResolvExpr/FindOpenVars.h \
    43       ResolvExpr/Occurs.cc \
    4437      ResolvExpr/PolyCost.cc \
    4538      ResolvExpr/PolyCost.hpp \
     
    5043      ResolvExpr/RenameVars.cc \
    5144      ResolvExpr/RenameVars.h \
    52       ResolvExpr/ResolveAssertions.cc \
    53       ResolvExpr/ResolveAssertions.h \
    5445      ResolvExpr/Resolver.cc \
    5546      ResolvExpr/Resolver.h \
     
    6152      ResolvExpr/SpecCost.cc \
    6253      ResolvExpr/SpecCost.hpp \
    63       ResolvExpr/TypeEnvironment.cc \
    64       ResolvExpr/TypeEnvironment.h \
    6554      ResolvExpr/typeops.h \
    6655      ResolvExpr/Unify.cc \
     
    6958
    7059SRC += $(SRC_RESOLVEXPR) \
    71         ResolvExpr/AlternativePrinter.cc \
    72         ResolvExpr/AlternativePrinter.h \
    7360        ResolvExpr/CandidatePrinter.cpp \
    7461        ResolvExpr/CandidatePrinter.hpp \
  • src/ResolvExpr/typeops.h

    r0030b508 rfc12f05  
    1919
    2020#include "AST/Type.hpp"
    21 #include "SynTree/Type.h"
    2221
    2322namespace SymTab {
     
    5251                        std::copy( i.begin(), i.end(), inserter );
    5352                        *out++ = result;
    54                 }
    55         }
    56 
    57         // in Occurs.cc
    58         bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env );
    59         // new AST version in TypeEnvironment.cpp (only place it was used in old AST)
    60 
    61         template<typename Iter>
    62         bool occursIn( Type* ty, Iter begin, Iter end, const TypeEnvironment & env ) {
    63                 while ( begin != end ) {
    64                         if ( occurs( ty, *begin, env ) ) return true;
    65                         ++begin;
    66                 }
    67                 return false;
    68         }
    69 
    70         /// flatten tuple type into list of types
    71         template< typename OutputIterator >
    72         void flatten( Type * type, OutputIterator out ) {
    73                 if ( TupleType * tupleType = dynamic_cast< TupleType * >( type ) ) {
    74                         for ( Type * t : tupleType->get_types() ) {
    75                                 flatten( t, out );
    76                         }
    77                 } else {
    78                         *out++ = type->clone();
    7953                }
    8054        }
     
    12094                return tupleFromTypes( tys.begin(), tys.end() );
    12195        }
    122 
    123         // in TypeEnvironment.cc
    124         bool isFtype( const Type * type );
    12596} // namespace ResolvExpr
    12697
  • src/SymTab/Demangle.cc

    r0030b508 rfc12f05  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Jul 19 12:52:41 2018
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 11 21:28:27 2021
    13 // Update Count     : 11
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  6 15:59:00 2023
     13// Update Count     : 12
    1414//
    1515
     
    1717#include <sstream>
    1818
     19#include "AST/Pass.hpp"
     20#include "AST/Type.hpp"
    1921#include "CodeGen/GenType.h"
    20 #include "Common/PassVisitor.h"
     22#include "CodeGen/OperatorTable.h"
    2123#include "Common/utility.h"                                                             // isPrefix
    2224#include "Mangler.h"
    23 #include "SynTree/Type.h"
    24 #include "SynTree/Declaration.h"
    2525
    2626#define DEBUG
     
    3131#endif
    3232
     33namespace Mangle {
     34
    3335namespace {
    34         struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
    35                 std::string typeString;
    36                 GenType( const std::string &typeString );
    37 
    38                 void previsit( BaseSyntaxNode * );
    39                 void postvisit( BaseSyntaxNode * );
    40 
    41                 void postvisit( FunctionType * funcType );
    42                 void postvisit( VoidType * voidType );
    43                 void postvisit( BasicType * basicType );
    44                 void postvisit( PointerType * pointerType );
    45                 void postvisit( ArrayType * arrayType );
    46                 void postvisit( ReferenceType * refType );
    47                 void postvisit( StructInstType * structInst );
    48                 void postvisit( UnionInstType * unionInst );
    49                 void postvisit( EnumInstType * enumInst );
    50                 void postvisit( TypeInstType * typeInst );
    51                 void postvisit( TupleType  * tupleType );
    52                 void postvisit( VarArgsType * varArgsType );
    53                 void postvisit( ZeroType * zeroType );
    54                 void postvisit( OneType * oneType );
    55                 void postvisit( GlobalScopeType * globalType );
    56                 void postvisit( QualifiedType * qualType );
    57 
    58           private:
    59                 void handleQualifiers( Type *type );
    60                 std::string handleGeneric( ReferenceToType * refType );
    61                 void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
    62         };
    63 
    64   std::string genDemangleType( Type * type, const std::string & baseString ) {
    65                 PassVisitor<GenType> gt( baseString );
    66                 assert( type );
    67                 type->accept( gt );
    68                 return gt.pass.typeString;
    69   }
    70 
    71         GenType::GenType( const std::string &typeString ) : typeString( typeString ) {}
    72 
    73         // *** BaseSyntaxNode
    74         void GenType::previsit( BaseSyntaxNode * ) {
    75                 // turn off automatic recursion for all nodes, to allow each visitor to
    76                 // precisely control the order in which its children are visited.
    77                 visit_children = false;
    78         }
    79 
    80         void GenType::postvisit( BaseSyntaxNode * node ) {
    81                 std::stringstream ss;
    82                 node->print( ss );
    83                 assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
    84         }
    85 
    86         void GenType::postvisit( VoidType * voidType ) {
    87                 typeString = "void " + typeString;
    88                 handleQualifiers( voidType );
    89         }
    90 
    91         void GenType::postvisit( BasicType * basicType ) {
    92                 BasicType::Kind kind = basicType->kind;
    93                 assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
    94                 typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
    95                 handleQualifiers( basicType );
    96         }
    97 
    98         void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool ) {
    99                 std::ostringstream os;
    100                 if ( typeString != "" ) {
    101                         if ( typeString[ 0 ] == '*' ) {
    102                                 os << "(" << typeString << ")";
    103                         } else {
    104                                 os << typeString;
    105                         } // if
    106                 } // if
    107                 os << "[";
    108 
    109                 if ( qualifiers.is_const ) {
    110                         os << "const ";
    111                 } // if
    112                 if ( qualifiers.is_volatile ) {
    113                         os << "volatile ";
    114                 } // if
    115                 if ( qualifiers.is_restrict ) {
    116                         os << "__restrict ";
    117                 } // if
    118                 if ( qualifiers.is_atomic ) {
    119                         os << "_Atomic ";
    120                 } // if
    121                 if ( dimension != 0 ) {
    122                         // TODO: ???
    123                         // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    124                         // dimension->accept( cg );
    125                 } else if ( isVarLen ) {
    126                         // no dimension expression on a VLA means it came in with the * token
    127                         os << "*";
    128                 } // if
    129                 os << "]";
    130 
    131                 typeString = os.str();
    132 
    133                 base->accept( *visitor );
    134         }
    135 
    136         void GenType::postvisit( PointerType * pointerType ) {
    137                 assert( pointerType->base != 0);
    138                 if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
    139                         assert(false);
    140                         genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
    141                 } else {
    142                         handleQualifiers( pointerType );
    143                         if ( typeString[ 0 ] == '?' ) {
    144                                 typeString = "* " + typeString;
    145                         } else {
    146                                 typeString = "*" + typeString;
    147                         } // if
    148                         pointerType->base->accept( *visitor );
    149                 } // if
    150         }
    151 
    152         void GenType::postvisit( ArrayType * arrayType ) {
    153                 genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
    154         }
    155 
    156         void GenType::postvisit( ReferenceType * refType ) {
    157                 assert( false );
    158                 assert( refType->base != 0);
    159                 handleQualifiers( refType );
    160                 typeString = "&" + typeString;
    161                 refType->base->accept( *visitor );
    162         }
    163 
    164         void GenType::postvisit( FunctionType * funcType ) {
    165                 std::ostringstream os;
    166 
    167                 if ( typeString != "" ) {
    168                         if ( typeString[0] == '*' ) {
    169                                 os << "(" << typeString << ")";
    170                         } else {
    171                                 os << typeString;
    172                         } // if
    173                 } // if
    174 
    175                 /************* parameters ***************/
    176                 const std::list<DeclarationWithType *> &pars = funcType->parameters;
    177 
    178                 if ( pars.empty() ) {
    179                         if ( funcType->get_isVarArgs() ) {
    180                                 os << "()";
    181                         } else {
    182                                 os << "(void)";
    183                         } // if
    184                 } else {
    185                         os << "(" ;
    186 
    187                         unsigned int i = 0;
    188                         for (DeclarationWithType * p : pars) {
    189                                 os << genDemangleType( p->get_type(), "" );
    190                                 if (++i != pars.size()) os << ", ";
    191                         }
    192 
    193                         if ( funcType->get_isVarArgs() ) {
    194                                 os << ", ...";
    195                         } // if
    196                         os << ")";
    197                 } // if
    198 
    199                 typeString = os.str();
    200 
    201                 if ( funcType->returnVals.size() == 0 ) {
    202                         typeString += ": void";
    203                 } else {
    204                         typeString += ": " + genDemangleType(funcType->returnVals.front()->get_type(), "");
    205                 } // if
    206 
    207                 // add forall
    208                 if( ! funcType->forall.empty() ) {
    209                         std::ostringstream os;
    210                         os << "forall(";
    211                         unsigned int i = 0;
    212                         for ( auto td : funcType->forall ) {
    213                                 os << td->typeString() << " " << td->name;
    214                                 if (! td->assertions.empty()) {
    215                                         os << " | { ";
    216                                         unsigned int j = 0;
    217                                         for (DeclarationWithType * assert : td->assertions) {
    218                                                 os << genDemangleType(assert->get_type(), assert->name);
    219                                                 if (++j != td->assertions.size()) os << ", ";
    220                                         }
    221                                         os << "}";
    222                                 }
    223                                 if (++i != funcType->forall.size()) os << ", ";
    224                         }
    225                         os << ")";
    226                         typeString = typeString + " -> " + os.str();
     36
     37struct Demangler {
     38private:
     39        std::string str;
     40        size_t index = 0;
     41        using Parser = std::function<ast::Type * ( ast::CV::Qualifiers )>;
     42        std::vector<std::pair<std::string, Parser>> parsers;
     43public:
     44        Demangler( const std::string & str );
     45
     46        bool done() const { return str.size() <= index; }
     47        char cur() const { assert( !done() ); return str[index]; }
     48        bool expect( char ch ) { return str[index++] == ch; }
     49
     50        bool isPrefix( const std::string & pref );
     51        bool extractNumber( size_t & out );
     52        bool extractName( std::string & out );
     53        bool stripMangleName( std::string & name );
     54
     55        ast::Type * parseFunction( ast::CV::Qualifiers tq );
     56        ast::Type * parseTuple( ast::CV::Qualifiers tq );
     57        ast::Type * parsePointer( ast::CV::Qualifiers tq );
     58        ast::Type * parseArray( ast::CV::Qualifiers tq );
     59        ast::Type * parseStruct( ast::CV::Qualifiers tq );
     60        ast::Type * parseUnion( ast::CV::Qualifiers tq );
     61        ast::Type * parseEnum( ast::CV::Qualifiers tq );
     62        ast::Type * parseType( ast::CV::Qualifiers tq );
     63        ast::Type * parseZero( ast::CV::Qualifiers tq );
     64        ast::Type * parseOne( ast::CV::Qualifiers tq );
     65
     66        ast::Type * parseType();
     67        bool parse( std::string & name, ast::Type *& type );
     68};
     69
     70Demangler::Demangler(const std::string & str) : str(str) {
     71        for (size_t k = 0; k < ast::BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
     72                parsers.emplace_back(Encoding::basicTypes[k], [k]( ast::CV::Qualifiers tq ) {
     73                        PRINT( std::cerr << "basic type: " << k << std::endl; )
     74                        return new ast::BasicType( (ast::BasicType::Kind)k, tq );
     75                });
     76        }
     77
     78        for (size_t k = 0; k < ast::TypeDecl::NUMBER_OF_KINDS; ++k) {
     79                static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };
     80                static_assert(
     81                        sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
     82                        "Each type variable kind should have a demangle name prefix"
     83                );
     84                parsers.emplace_back(Encoding::typeVariables[k], [k, this]( ast::CV::Qualifiers tq ) -> ast::TypeInstType * {
     85                        PRINT( std::cerr << "type variable type: " << k << std::endl; )
     86                        size_t N;
     87                        if (!extractNumber(N)) return nullptr;
     88                        return new ast::TypeInstType(
     89                                toString(typeVariableNames[k], N),
     90                                (ast::TypeDecl::Kind)k,
     91                                tq );
     92                });
     93        }
     94
     95        parsers.emplace_back(Encoding::void_t, [this]( ast::CV::Qualifiers tq ) { return new ast::VoidType(tq); });
     96        parsers.emplace_back(Encoding::function, [this]( ast::CV::Qualifiers tq ) { return parseFunction(tq); });
     97        parsers.emplace_back(Encoding::pointer, [this]( ast::CV::Qualifiers tq ) { return parsePointer(tq); });
     98        parsers.emplace_back(Encoding::array, [this]( ast::CV::Qualifiers tq ) { return parseArray(tq); });
     99        parsers.emplace_back(Encoding::tuple, [this]( ast::CV::Qualifiers tq ) { return parseTuple(tq); });
     100        parsers.emplace_back(Encoding::struct_t, [this]( ast::CV::Qualifiers tq ) { return parseStruct(tq); });
     101        parsers.emplace_back(Encoding::union_t, [this]( ast::CV::Qualifiers tq ) { return parseUnion(tq); });
     102        parsers.emplace_back(Encoding::enum_t, [this]( ast::CV::Qualifiers tq ) { return parseEnum(tq); });
     103        parsers.emplace_back(Encoding::type, [this]( ast::CV::Qualifiers tq ) { return parseType(tq); });
     104        parsers.emplace_back(Encoding::zero, []( ast::CV::Qualifiers tq ) { return new ast::ZeroType(tq); });
     105        parsers.emplace_back(Encoding::one, []( ast::CV::Qualifiers tq ) { return new ast::OneType(tq); });
     106}
     107
     108bool Demangler::extractNumber( size_t & out ) {
     109        std::stringstream numss;
     110        if ( str.size() <= index ) return false;
     111        while ( isdigit( str[index] ) ) {
     112                numss << str[index];
     113                ++index;
     114                if ( str.size() == index ) break;
     115        }
     116        if ( !(numss >> out) ) return false;
     117        PRINT( std::cerr << "extractNumber success: " << out << std::endl; )
     118        return true;
     119}
     120
     121bool Demangler::extractName( std::string & out ) {
     122        size_t len;
     123        if ( !extractNumber(len) ) return false;
     124        if ( str.size() < index + len ) return false;
     125        out = str.substr( index, len );
     126        index += len;
     127        PRINT( std::cerr << "extractName success: " << out << std::endl; )
     128        return true;
     129}
     130
     131bool Demangler::isPrefix( const std::string & pref ) {
     132        // Wraps the utility isPrefix function.
     133        if ( ::isPrefix( str, pref, index ) ) {
     134                index += pref.size();
     135                return true;
     136        }
     137        return false;
     138}
     139
     140// strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
     141bool Demangler::stripMangleName( std::string & name ) {
     142        PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
     143        if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
     144        if ( !isPrefix(Encoding::manglePrefix) || !isdigit(str.back() ) ) return false;
     145
     146        if (!extractName(name)) return false;
     147
     148        // Find bounds for type.
     149        PRINT( std::cerr << index << " " << str.size() << std::endl; )
     150        PRINT( std::cerr << "[");
     151        while (isdigit(str.back())) {
     152                PRINT(std::cerr << ".");
     153                str.pop_back();
     154                if (str.size() <= index) return false;
     155        }
     156        PRINT( std::cerr << "]" << std::endl );
     157        if (str.back() != '_') return false;
     158        str.pop_back();
     159        PRINT( std::cerr << str.size() << " " << name << " " << str.substr(index) << std::endl; )
     160        return index < str.size();
     161}
     162
     163ast::Type * Demangler::parseFunction( ast::CV::Qualifiers tq ) {
     164        PRINT( std::cerr << "function..." << std::endl; )
     165        if ( done() ) return nullptr;
     166        ast::FunctionType * ftype = new ast::FunctionType( ast::FixedArgs, tq );
     167        std::unique_ptr<ast::Type> manager( ftype );
     168        ast::Type * retVal = parseType();
     169        if ( !retVal ) return nullptr;
     170        PRINT( std::cerr << "with return type: " << retVal << std::endl; )
     171        ftype->returns.emplace_back( retVal );
     172        if ( done() || !expect('_') ) return nullptr;
     173        while ( !done() ) {
     174                PRINT( std::cerr << "got ch: " << cur() << std::endl; )
     175                if ( cur() == '_' ) return manager.release();
     176                ast::Type * param = parseType();
     177                if ( !param ) return nullptr;
     178                PRINT( std::cerr << "with parameter : " << param << std::endl; )
     179                ftype->params.emplace_back( param );
     180        }
     181        return nullptr;
     182}
     183
     184ast::Type * Demangler::parseTuple( ast::CV::Qualifiers tq ) {
     185        PRINT( std::cerr << "tuple..." << std::endl; )
     186        std::vector<ast::ptr<ast::Type>> types;
     187        size_t ncomponents;
     188        if ( !extractNumber(ncomponents) ) return nullptr;
     189        for ( size_t i = 0; i < ncomponents; ++i ) {
     190                if ( done() ) return nullptr;
     191                PRINT( std::cerr << "got ch: " << cur() << std::endl; )
     192                ast::Type * t = parseType();
     193                if ( !t ) return nullptr;
     194                PRINT( std::cerr << "with type : " << t << std::endl; )
     195                types.push_back( t );
     196        }
     197        return new ast::TupleType( std::move( types ), tq );
     198}
     199
     200ast::Type * Demangler::parsePointer( ast::CV::Qualifiers tq ) {
     201        PRINT( std::cerr << "pointer..." << std::endl; )
     202        ast::Type * t = parseType();
     203        if ( !t ) return nullptr;
     204        return new ast::PointerType( t, tq );
     205}
     206
     207ast::Type * Demangler::parseArray( ast::CV::Qualifiers tq ) {
     208        PRINT( std::cerr << "array..." << std::endl; )
     209        size_t length;
     210        if ( !extractNumber(length) ) return nullptr;
     211        ast::Type * t = parseType();
     212        if ( !t ) return nullptr;
     213        return new ast::ArrayType(
     214                t,
     215                ast::ConstantExpr::from_ulong( CodeLocation(), length ),
     216                ast::FixedLen,
     217                ast::DynamicDim,
     218                tq );
     219}
     220
     221ast::Type * Demangler::parseStruct( ast::CV::Qualifiers tq ) {
     222        PRINT( std::cerr << "struct..." << std::endl; )
     223        std::string name;
     224        if ( !extractName(name) ) return nullptr;
     225        return new ast::StructInstType( name, tq );
     226}
     227
     228ast::Type * Demangler::parseUnion( ast::CV::Qualifiers tq ) {
     229        PRINT( std::cerr << "union..." << std::endl; )
     230        std::string name;
     231        if ( !extractName(name) ) return nullptr;
     232        return new ast::UnionInstType( name, tq );
     233}
     234
     235ast::Type * Demangler::parseEnum( ast::CV::Qualifiers tq ) {
     236        PRINT( std::cerr << "enum..." << std::endl; )
     237        std::string name;
     238        if ( !extractName(name) ) return nullptr;
     239        return new ast::EnumInstType( name, tq );
     240}
     241
     242ast::Type * Demangler::parseType( ast::CV::Qualifiers tq ) {
     243        PRINT( std::cerr << "type..." << std::endl; )
     244        std::string name;
     245        if ( !extractName(name) ) return nullptr;
     246        PRINT( std::cerr << "typename..." << name << std::endl; )
     247        return new ast::TypeInstType( name, ast::TypeDecl::Dtype, tq );
     248}
     249
     250ast::Type * Demangler::parseType() {
     251        if (done()) return nullptr;
     252
     253        if (isPrefix(Encoding::forall)) {
     254                PRINT( std::cerr << "polymorphic with..." << std::endl; )
     255                size_t dcount, fcount, vcount, acount;
     256                if ( !extractNumber(dcount) ) return nullptr;
     257                PRINT( std::cerr << dcount << " dtypes" << std::endl; )
     258                if ( !expect('_') ) return nullptr;
     259                if ( !extractNumber(fcount) ) return nullptr;
     260                PRINT( std::cerr << fcount << " ftypes" << std::endl; )
     261                if ( !expect('_')) return nullptr;
     262                if ( !extractNumber(vcount)) return nullptr;
     263                PRINT( std::cerr << vcount << " ttypes" << std::endl; )
     264                if ( !expect('_') ) return nullptr;
     265                if ( !extractNumber(acount) ) return nullptr;
     266                PRINT( std::cerr << acount << " assertions" << std::endl; )
     267                if ( !expect('_') ) return nullptr;
     268                for ( size_t i = 0 ; i < acount ; ++i ) {
     269                        // TODO: need to recursively parse assertions, but for now just return nullptr so that
     270                        // demangler does not crash if there are assertions
     271                        return nullptr;
    227272                }
    228         }
    229 
    230         std::string GenType::handleGeneric( ReferenceToType * refType ) {
    231                 if ( ! refType->parameters.empty() ) {
    232                         std::ostringstream os;
    233                         // TODO: ???
    234                         // PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
    235                         os << "(";
    236                         // cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
    237                         os << ") ";
    238                         return os.str();
    239                 }
    240                 return "";
    241         }
    242 
    243         void GenType::postvisit( StructInstType * structInst )  {
    244                 typeString = "struct " + structInst->name + handleGeneric( structInst ) + " " + typeString;
    245                 handleQualifiers( structInst );
    246         }
    247 
    248         void GenType::postvisit( UnionInstType * unionInst ) {
    249                 typeString = "union " + unionInst->name + handleGeneric( unionInst ) + " " + typeString;
    250                 handleQualifiers( unionInst );
    251         }
    252 
    253         void GenType::postvisit( EnumInstType * enumInst ) {
    254                 typeString = "enum " + enumInst->name + " " + typeString;
    255                 handleQualifiers( enumInst );
    256         }
    257 
    258         void GenType::postvisit( TypeInstType * typeInst ) {
    259                 typeString = typeInst->name + " " + typeString;
    260                 handleQualifiers( typeInst );
    261         }
    262 
    263         void GenType::postvisit( TupleType * tupleType ) {
    264                 unsigned int i = 0;
    265                 std::ostringstream os;
    266                 os << "[";
    267                 for ( Type * t : *tupleType ) {
    268                         i++;
    269                         os << genDemangleType( t, "" ) << (i == tupleType->size() ? "" : ", ");
    270                 }
    271                 os << "] ";
    272                 typeString = os.str() + typeString;
    273         }
    274 
    275         void GenType::postvisit( VarArgsType * varArgsType ) {
    276                 typeString = "__builtin_va_list " + typeString;
    277                 handleQualifiers( varArgsType );
    278         }
    279 
    280         void GenType::postvisit( ZeroType * zeroType ) {
    281                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    282                 typeString = "zero_t " + typeString;
    283                 handleQualifiers( zeroType );
    284         }
    285 
    286         void GenType::postvisit( OneType * oneType ) {
    287                 // ideally these wouldn't hit codegen at all, but should be safe to make them ints
    288                 typeString = "one_t " + typeString;
    289                 handleQualifiers( oneType );
    290         }
    291 
    292         void GenType::postvisit( GlobalScopeType * globalType ) {
    293                 handleQualifiers( globalType );
    294         }
    295 
    296         void GenType::postvisit( QualifiedType * qualType ) {
    297                 std::ostringstream os;
    298                 os << genDemangleType( qualType->parent, "" ) << "." << genDemangleType( qualType->child, "" ) << typeString;
    299                 typeString = os.str();
    300                 handleQualifiers( qualType );
    301         }
    302 
    303         void GenType::handleQualifiers( Type * type ) {
    304                 if ( type->get_const() ) {
    305                         typeString = "const " + typeString;
    306                 } // if
    307                 if ( type->get_volatile() ) {
    308                         typeString = "volatile " + typeString;
    309                 } // if
    310                 if ( type->get_restrict() ) {
    311                         typeString = "__restrict " + typeString;
    312                 } // if
    313                 if ( type->get_atomic() ) {
    314                         typeString = "_Atomic " + typeString;
    315                 } // if
    316         }
    317 }
    318 
    319 
    320 namespace SymTab {
    321         namespace Mangler {
    322                 namespace {
    323                         struct StringView {
    324                         private:
    325                                 std::string str;
    326                                 size_t idx = 0;
    327                                 // typedef Type * (StringView::*parser)(Type::Qualifiers);
    328                                 typedef std::function<Type * (Type::Qualifiers)> parser;
    329                                 std::vector<std::pair<std::string, parser>> parsers;
    330                         public:
    331                                 StringView(const std::string & str);
    332 
    333                                 bool done() const { return idx >= str.size(); }
    334                                 char cur() const { assert(! done()); return str[idx]; }
    335 
    336                                 bool expect(char ch) { return str[idx++] == ch; }
    337                                 void next(size_t inc = 1) { idx += inc; }
    338 
    339                                 /// determines if `pref` is a prefix of `str`
    340                                 bool isPrefix(const std::string & pref);
    341                                 bool extractNumber(size_t & out);
    342                                 bool extractName(std::string & out);
    343                                 bool stripMangleName(std::string & name);
    344 
    345                                 Type * parseFunction(Type::Qualifiers tq);
    346                                 Type * parseTuple(Type::Qualifiers tq);
    347                                 Type * parseVoid(Type::Qualifiers tq);
    348                                 Type * parsePointer(Type::Qualifiers tq);
    349                                 Type * parseArray(Type::Qualifiers tq);
    350                                 Type * parseStruct(Type::Qualifiers tq);
    351                                 Type * parseUnion(Type::Qualifiers tq);
    352                                 Type * parseEnum(Type::Qualifiers tq);
    353                                 Type * parseType(Type::Qualifiers tq);
    354 
    355                                 Type * parseType();
    356                                 bool parse(std::string & name, Type *& type);
    357                         };
    358 
    359                         StringView::StringView(const std::string & str) : str(str) {
    360                                 // basic types
    361                                 for (size_t k = 0; k < BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
    362                                         parsers.emplace_back(Encoding::basicTypes[k], [k](Type::Qualifiers tq) {
    363                                                 PRINT( std::cerr << "basic type: " << k << std::endl; )
    364                                                 return new BasicType(tq, (BasicType::Kind)k);
    365                                         });
    366                                 }
    367                                 // type variable types
    368                                 for (size_t k = 0; k < TypeDecl::NUMBER_OF_KINDS; ++k) {
    369                                         static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };
    370                                         static_assert(
    371                                                 sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == TypeDecl::NUMBER_OF_KINDS,
    372                                                 "Each type variable kind should have a demangle name prefix"
    373                                         );
    374                                         parsers.emplace_back(Encoding::typeVariables[k], [k, this](Type::Qualifiers tq) -> TypeInstType * {
    375                                                 PRINT( std::cerr << "type variable type: " << k << std::endl; )
    376                                                 size_t N;
    377                                                 if (! extractNumber(N)) return nullptr;
    378                                                 return new TypeInstType(tq, toString(typeVariableNames[k], N), (TypeDecl::Kind)k != TypeDecl::Ftype);
    379                                         });
    380                                 }
    381                                 // everything else
    382                                 parsers.emplace_back(Encoding::void_t, [this](Type::Qualifiers tq) { return parseVoid(tq); });
    383                                 parsers.emplace_back(Encoding::function, [this](Type::Qualifiers tq) { return parseFunction(tq); });
    384                                 parsers.emplace_back(Encoding::pointer, [this](Type::Qualifiers tq) { return parsePointer(tq); });
    385                                 parsers.emplace_back(Encoding::array, [this](Type::Qualifiers tq) { return parseArray(tq); });
    386                                 parsers.emplace_back(Encoding::tuple, [this](Type::Qualifiers tq) { return parseTuple(tq); });
    387                                 parsers.emplace_back(Encoding::struct_t, [this](Type::Qualifiers tq) { return parseStruct(tq); });
    388                                 parsers.emplace_back(Encoding::union_t, [this](Type::Qualifiers tq) { return parseUnion(tq); });
    389                                 parsers.emplace_back(Encoding::enum_t, [this](Type::Qualifiers tq) { return parseEnum(tq); });
    390                                 parsers.emplace_back(Encoding::type, [this](Type::Qualifiers tq) { return parseType(tq); });
    391                                 parsers.emplace_back(Encoding::zero, [](Type::Qualifiers tq) { return new ZeroType(tq); });
    392                                 parsers.emplace_back(Encoding::one, [](Type::Qualifiers tq) { return new OneType(tq); });
    393                         }
    394 
    395                         bool StringView::extractNumber(size_t & out) {
    396                                 std::stringstream numss;
    397                                 if (idx >= str.size()) return false;
    398                                 while (isdigit(str[idx])) {
    399                                         numss << str[idx];
    400                                         ++idx;
    401                                         if (idx == str.size()) break;
    402                                 }
    403                                 if (! (numss >> out)) return false;
    404                                 PRINT( std::cerr << "extractNumber success: " << out << std::endl; )
    405                                 return true;
    406                         }
    407 
    408                         bool StringView::extractName(std::string & out) {
    409                                 size_t len;
    410                                 if (! extractNumber(len)) return false;
    411                                 if (idx+len > str.size()) return false;
    412                                 out = str.substr(idx, len);
    413                                 idx += len;
    414                                 PRINT( std::cerr << "extractName success: " << out << std::endl; )
    415                                 return true;
    416                         }
    417 
    418                         bool StringView::isPrefix(const std::string & pref) {
    419                                 // if ( pref.size() > str.size()-idx ) return false;
    420                                 // auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
    421                                 // if (its.first == pref.end()) {
    422                                 //      idx += pref.size();
    423                                 //      return true;
    424                                 // }
    425 
    426                                 // This update is untested because there are no tests for this code.
    427                                 if ( ::isPrefix( str, pref, idx ) ) {
    428                                         idx += pref.size();
    429                                         return true;
    430                                 }
    431                                 return false;
    432                         }
    433 
    434                         // strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
    435                         bool StringView::stripMangleName(std::string & name) {
    436                                 PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
    437                                 if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
    438                                 if ( ! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back() ) ) return false;
    439 
    440                                 // get name
    441                                 if (! extractName(name)) return false;
    442 
    443                                 // find bounds for type
    444                                 PRINT( std::cerr << idx << " " << str.size() << std::endl; )
    445                                 PRINT( std::cerr << "[");
    446                                 while (isdigit(str.back())) {
    447                                         PRINT(std::cerr << ".");
    448                                         str.pop_back();
    449                                         if (str.size() <= idx) return false;
    450                                 }
    451                                 PRINT( std::cerr << "]" << std::endl );
    452                                 if (str.back() != '_') return false;
    453                                 str.pop_back();
    454                                 PRINT( std::cerr << str.size() << " " << name << " " << str.substr(idx) << std::endl; )
    455                                 return str.size() > idx;
    456                         }
    457 
    458                         Type * StringView::parseFunction(Type::Qualifiers tq) {
    459                                 PRINT( std::cerr << "function..." << std::endl; )
    460                                 if (done()) return nullptr;
    461                                 FunctionType * ftype = new FunctionType( tq, false );
    462                                 std::unique_ptr<Type> manager(ftype);
    463                                 Type * retVal = parseType();
    464                                 if (! retVal) return nullptr;
    465                                 PRINT( std::cerr << "with return type: " << retVal << std::endl; )
    466                                 ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr));
    467                                 if (done() || ! expect('_')) return nullptr;
    468                                 while (! done()) {
    469                                         PRINT( std::cerr << "got ch: " << cur() << std::endl; )
    470                                         if (cur() == '_') return manager.release();
    471                                         Type * param = parseType();
    472                                         if (! param) return nullptr;
    473                                         PRINT( std::cerr << "with parameter : " << param << std::endl; )
    474                                         ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr));
    475                                 }
    476                                 return nullptr;
    477                         }
    478 
    479                         Type * StringView::parseTuple(Type::Qualifiers tq) {
    480                                 PRINT( std::cerr << "tuple..." << std::endl; )
    481                                 std::list< Type * > types;
    482                                 size_t ncomponents;
    483                                 if (! extractNumber(ncomponents)) return nullptr;
    484                                 for (size_t i = 0; i < ncomponents; ++i) {
    485                                         // TODO: delete all on return
    486                                         if (done()) return nullptr;
    487                                         PRINT( std::cerr << "got ch: " << cur() << std::endl; )
    488                                         Type * t = parseType();
    489                                         if (! t) return nullptr;
    490                                         PRINT( std::cerr << "with type : " << t << std::endl; )
    491                                         types.push_back(t);
    492                                 }
    493                                 return new TupleType( tq, types );
    494                         }
    495 
    496                         Type * StringView::parseVoid(Type::Qualifiers tq) {
    497                                 return new VoidType( tq );
    498                         }
    499 
    500                         Type * StringView::parsePointer(Type::Qualifiers tq) {
    501                                 PRINT( std::cerr << "pointer..." << std::endl; )
    502                                 Type * t = parseType();
    503                                 if (! t) return nullptr;
    504                                 return new PointerType( tq, t );
    505                         }
    506 
    507                         Type * StringView::parseArray(Type::Qualifiers tq) {
    508                                 PRINT( std::cerr << "array..." << std::endl; )
    509                                 size_t length;
    510                                 if (! extractNumber(length)) return nullptr;
    511                                 Type * t = parseType();
    512                                 if (! t) return nullptr;
    513                                 return new ArrayType( tq, t, new ConstantExpr( Constant::from_ulong(length) ), false, false );
    514                         }
    515 
    516                         Type * StringView::parseStruct(Type::Qualifiers tq) {
    517                                 PRINT( std::cerr << "struct..." << std::endl; )
    518                                 std::string name;
    519                                 if (! extractName(name)) return nullptr;
    520                                 return new StructInstType(tq, name);
    521                         }
    522 
    523                         Type * StringView::parseUnion(Type::Qualifiers tq) {
    524                                 PRINT( std::cerr << "union..." << std::endl; )
    525                                 std::string name;
    526                                 if (! extractName(name)) return nullptr;
    527                                 return new UnionInstType(tq, name);
    528                         }
    529 
    530                         Type * StringView::parseEnum(Type::Qualifiers tq) {
    531                                 PRINT( std::cerr << "enum..." << std::endl; )
    532                                 std::string name;
    533                                 if (! extractName(name)) return nullptr;
    534                                 return new EnumInstType(tq, name);
    535                         }
    536 
    537                         Type * StringView::parseType(Type::Qualifiers tq) {
    538                                 PRINT( std::cerr << "type..." << std::endl; )
    539                                 std::string name;
    540                                 if (! extractName(name)) return nullptr;
    541                                 PRINT( std::cerr << "typename..." << name << std::endl; )
    542                                 return new TypeInstType(tq, name, false);
    543                         }
    544 
    545                         Type * StringView::parseType() {
    546                                 if (done()) return nullptr;
    547 
    548                                 std::list<TypeDecl *> forall;
    549                                 if (isPrefix(Encoding::forall)) {
    550                                         PRINT( std::cerr << "polymorphic with..." << std::endl; )
    551                                         size_t dcount, fcount, vcount, acount;
    552                                         if (! extractNumber(dcount)) return nullptr;
    553                                         PRINT( std::cerr << dcount << " dtypes" << std::endl; )
    554                                         if (! expect('_')) return nullptr;
    555                                         if (! extractNumber(fcount)) return nullptr;
    556                                         PRINT( std::cerr << fcount << " ftypes" << std::endl; )
    557                                         if (! expect('_')) return nullptr;
    558                                         if (! extractNumber(vcount)) return nullptr;
    559                                         PRINT( std::cerr << vcount << " ttypes" << std::endl; )
    560                                         if (! expect('_')) return nullptr;
    561                                         if (! extractNumber(acount)) return nullptr;
    562                                         PRINT( std::cerr << acount << " assertions" << std::endl; )
    563                                         if (! expect('_')) return nullptr;
    564                                         for (size_t i = 0; i < acount; ++i) {
    565                                                 // TODO: need to recursively parse assertions, but for now just return nullptr so that
    566                                                 // demangler does not crash if there are assertions
    567                                                 return nullptr;
    568                                         }
    569                                         if (! expect('_')) return nullptr;
    570                                 }
    571 
    572                                 // qualifiers
    573                                 Type::Qualifiers tq;
    574                                 while (true) {
    575                                         auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
    576                                                 return isPrefix(val.second);
    577                                         });
    578                                         if (qual == Encoding::qualifiers.end()) break;
    579                                         tq |= qual->first;
    580                                 }
    581 
    582                                 // find the correct type parser and use it
    583                                 auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, parser> & p) {
    584                                         return isPrefix(p.first);
    585                                 });
    586                                 assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), idx);
    587                                 Type * ret = iter->second(tq);
    588                                 if (! ret) return nullptr;
    589                                 ret->forall = std::move(forall);
    590                                 return ret;
    591                         }
    592 
    593                         bool StringView::parse(std::string & name, Type *& type) {
    594                                 if (! stripMangleName(name)) return false;
    595                                 PRINT( std::cerr << "stripped name: " << name << std::endl; )
    596                                 Type * t = parseType();
    597                                 if (! t) return false;
    598                                 type = t;
    599                                 return true;
    600                         }
    601 
    602                         std::string demangle(const std::string & mangleName) {
    603                                 SymTab::Mangler::StringView view(mangleName);
    604                                 std::string name;
    605                                 Type * type = nullptr;
    606                                 if (! view.parse(name, type)) return mangleName;
    607                                 std::unique_ptr<Type> manager(type);
    608                                 return genDemangleType(type, name);
    609                         }
    610                 } // namespace
    611         } // namespace Mangler
    612 } // namespace SymTab
     273                if ( !expect('_') ) return nullptr;
     274        }
     275
     276        ast::CV::Qualifiers tq;
     277        while (true) {
     278                auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
     279                        return isPrefix(val.second);
     280                });
     281                if (qual == Encoding::qualifiers.end()) break;
     282                tq |= qual->first;
     283        }
     284
     285        // Find the correct type parser and then apply it.
     286        auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, Parser> & p) {
     287                return isPrefix(p.first);
     288        });
     289        assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), index);
     290        ast::Type * ret = iter->second(tq);
     291        if ( !ret ) return nullptr;
     292        return ret;
     293}
     294
     295bool Demangler::parse( std::string & name, ast::Type *& type) {
     296        if ( !stripMangleName(name) ) return false;
     297        PRINT( std::cerr << "stripped name: " << name << std::endl; )
     298        ast::Type * t = parseType();
     299        if ( !t ) return false;
     300        type = t;
     301        return true;
     302}
     303
     304std::string demangle( const std::string & mangleName ) {
     305        using namespace CodeGen;
     306        Demangler demangler( mangleName );
     307        std::string name;
     308        ast::Type * type = nullptr;
     309        if ( !demangler.parse( name, type ) ) return mangleName;
     310        ast::readonly<ast::Type> roType = type;
     311        if ( auto info = operatorLookupByOutput( name ) ) name = info->inputName;
     312        return genType( type, name, Options( false, false, false, false ) );
     313}
     314
     315} // namespace
     316
     317} // namespace Mangle
    613318
    614319extern "C" {
    615320        char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) {
    616                 const std::string & demangleName = SymTab::Mangler::demangle(mangleName);
     321                const std::string & demangleName = Mangle::demangle(mangleName);
    617322                return strdup(demangleName.c_str());
    618323        }
  • src/SymTab/Demangle.h

    r0030b508 rfc12f05  
    1010// Created On       : Fri May 13 10:11:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri May 13 10:30:00 2022
    13 // Update Count     : 0
     12// Last Modified On : Mon Nov  6 15:48:00 2023
     13// Update Count     : 1
    1414//
    1515
     
    1717
    1818extern "C" {
     19        /// Main interface to the demangler as a utility.
     20        /// Caller must free the returned string.
    1921        char * cforall_demangle(const char *, int);
    2022}
  • src/SymTab/FixFunction.cc

    r0030b508 rfc12f05  
    2222#include "AST/Type.hpp"
    2323#include "Common/utility.h"       // for copy
    24 #include "SynTree/Declaration.h"  // for FunctionDecl, ObjectDecl, Declarati...
    25 #include "SynTree/Expression.h"   // for Expression
    26 #include "SynTree/Type.h"         // for ArrayType, PointerType, Type, Basic...
    2724
    2825namespace SymTab {
    29         class FixFunction_old : public WithShortCircuiting {
    30                 typedef Mutator Parent;
    31           public:
    32                 FixFunction_old() : isVoid( false ) {}
    33 
    34                 void premutate(FunctionDecl *functionDecl);
    35                 DeclarationWithType* postmutate(FunctionDecl *functionDecl);
    36 
    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) {
    57                 // can't delete function type because it may contain assertions, so transfer ownership to new object
    58                 ObjectDecl *pointer = new ObjectDecl( functionDecl->name, functionDecl->get_storageClasses(), functionDecl->linkage, nullptr, new PointerType( Type::Qualifiers(), functionDecl->type ), nullptr, functionDecl->attributes );
    59                 pointer->location = functionDecl->location;
    60                 functionDecl->attributes.clear();
    61                 functionDecl->type = nullptr;
    62                 delete functionDecl;
    63                 return pointer;
    64         }
    65 
    66         // xxx - this passes on void[], e.g.
    67         //   void foo(void [10]);
    68         // does not cause an error
    69 
    70         Type * FixFunction_old::postmutate(ArrayType *arrayType) {
    71                 // need to recursively mutate the base type in order for multi-dimensional arrays to work.
    72                 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->isVarLen, arrayType->isStatic );
    73                 pointerType->location = arrayType->location;
    74                 arrayType->base = nullptr;
    75                 arrayType->dimension = nullptr;
    76                 delete arrayType;
    77                 return pointerType;
    78         }
    79 
    80         void FixFunction_old::premutate(VoidType *) {
    81                 isVoid = true;
    82         }
    83 
    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; }
    97 
    98         bool fixFunction( DeclarationWithType *& dwt ) {
    99                 PassVisitor<FixFunction_old> fixer;
    100                 dwt = dwt->acceptMutator( fixer );
    101                 return fixer.pass.isVoid;
    102         }
    10326
    10427namespace {
  • src/SymTab/FixFunction.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include "Common/PassVisitor.h" // for PassVisitor
    19 #include "SynTree/SynTree.h"    // for Types
    20 
    2118namespace ast {
    2219        class DeclWithType;
     
    2522
    2623namespace SymTab {
    27         /// Replaces function and array types by equivalent pointer types. Returns true if type is
    28         /// void
    29         bool fixFunction( DeclarationWithType *& );
    30 
    3124        /// Returns declaration with function and array types replaced by equivalent pointer types.
    3225        /// Sets isVoid to true if type is void
  • src/SymTab/Mangler.cc

    r0030b508 rfc12f05  
    2222#include <string>                        // for string, char_traits, operator<<
    2323
     24#include "AST/Pass.hpp"
    2425#include "CodeGen/OperatorTable.h"       // for OperatorInfo, operatorLookup
    25 #include "Common/PassVisitor.h"
    2626#include "Common/ToString.hpp"           // for toCString
    2727#include "Common/SemanticError.h"        // for SemanticError
    28 #include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    29 #include "SynTree/LinkageSpec.h"         // for Spec, isOverridable, AutoGen, Int...
    30 #include "SynTree/Declaration.h"         // for TypeDecl, DeclarationWithType
    31 #include "SynTree/Expression.h"          // for TypeExpr, Expression, operator<<
    32 #include "SynTree/Type.h"                // for Type, ReferenceToType, Type::Fora...
    33 
    34 #include "AST/Pass.hpp"
    35 
    36 namespace SymTab {
    37         namespace Mangler {
    38                 namespace {
    39                         /// Mangles names to a unique C identifier
    40                         struct Mangler_old : public WithShortCircuiting, public WithVisitorRef<Mangler_old>, public WithGuards {
    41                                 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
    42                                 Mangler_old( const Mangler_old & ) = delete;
    43 
    44                                 void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    45 
    46                                 void postvisit( const ObjectDecl * declaration );
    47                                 void postvisit( const FunctionDecl * declaration );
    48                                 void postvisit( const TypeDecl * declaration );
    49 
    50                                 void postvisit( const VoidType * voidType );
    51                                 void postvisit( const BasicType * basicType );
    52                                 void postvisit( const PointerType * pointerType );
    53                                 void postvisit( const ArrayType * arrayType );
    54                                 void postvisit( const ReferenceType * refType );
    55                                 void postvisit( const FunctionType * functionType );
    56                                 void postvisit( const StructInstType * aggregateUseType );
    57                                 void postvisit( const UnionInstType * aggregateUseType );
    58                                 void postvisit( const EnumInstType * aggregateUseType );
    59                                 void postvisit( const TypeInstType * aggregateUseType );
    60                                 void postvisit( const TraitInstType * inst );
    61                                 void postvisit( const TupleType * tupleType );
    62                                 void postvisit( const VarArgsType * varArgsType );
    63                                 void postvisit( const ZeroType * zeroType );
    64                                 void postvisit( const OneType * oneType );
    65                                 void postvisit( const QualifiedType * qualType );
    66 
    67                                 std::string get_mangleName() { return mangleName; }
    68                           private:
    69                                 std::string mangleName;         ///< Mangled name being constructed
    70                                 typedef std::map< std::string, std::pair< int, int > > VarMapType;
    71                                 VarMapType varNums;             ///< Map of type variables to indices
    72                                 int nextVarNum;                 ///< Next type variable index
    73                                 bool isTopLevel;                ///< Is the Mangler at the top level
    74                                 bool mangleOverridable;         ///< Specially mangle overridable built-in methods
    75                                 bool typeMode;                  ///< Produce a unique mangled name for a type
    76                                 bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
    77                                 bool inFunctionType = false;    ///< Include type qualifiers if false.
    78                                 bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
    79 
    80                           public:
    81                                 Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    82                                         int nextVarNum, const VarMapType& varNums );
    83 
    84                           private:
    85                                 void mangleDecl( const DeclarationWithType * declaration );
    86                                 void mangleRef( const ReferenceToType * refType, std::string prefix );
    87 
    88                                 void printQualifiers( const Type *type );
    89                         }; // Mangler_old
    90                 } // namespace
    91 
    92                 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {
    93                         PassVisitor<Mangler_old> mangler( mangleOverridable, typeMode, mangleGenericParams );
    94                         maybeAccept( decl, mangler );
    95                         return mangler.pass.get_mangleName();
    96                 }
    97 
    98                 std::string mangleType( const Type * ty ) {
    99                         PassVisitor<Mangler_old> mangler( false, true, true );
    100                         maybeAccept( ty, mangler );
    101                         return mangler.pass.get_mangleName();
    102                 }
    103 
    104                 std::string mangleConcrete( const Type * ty ) {
    105                         PassVisitor<Mangler_old> mangler( false, false, false );
    106                         maybeAccept( ty, mangler );
    107                         return mangler.pass.get_mangleName();
    108                 }
    109 
    110                 namespace {
    111                         Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
    112                                 : nextVarNum( 0 ), isTopLevel( true ),
    113                                 mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    114                                 mangleGenericParams( mangleGenericParams ) {}
    115 
    116                         Mangler_old::Mangler_old( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
    117                                 int nextVarNum, const VarMapType& varNums )
    118                                 : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
    119                                 mangleOverridable( mangleOverridable ), typeMode( typeMode ),
    120                                 mangleGenericParams( mangleGenericParams ) {}
    121 
    122                         void Mangler_old::mangleDecl( const DeclarationWithType * declaration ) {
    123                                 bool wasTopLevel = isTopLevel;
    124                                 if ( isTopLevel ) {
    125                                         varNums.clear();
    126                                         nextVarNum = 0;
    127                                         isTopLevel = false;
    128                                 } // if
    129                                 mangleName += Encoding::manglePrefix;
    130                                 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );
    131                                 if ( opInfo ) {
    132                                         mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
    133                                 } else {
    134                                         mangleName += std::to_string( declaration->name.size() ) + declaration->name;
    135                                 } // if
    136                                 maybeAccept( declaration->get_type(), *visitor );
    137                                 if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
    138                                         // want to be able to override autogenerated and intrinsic routines,
    139                                         // so they need a different name mangling
    140                                         if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
    141                                                 mangleName += Encoding::autogen;
    142                                         } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
    143                                                 mangleName += Encoding::intrinsic;
    144                                         } else {
    145                                                 // if we add another kind of overridable function, this has to change
    146                                                 assert( false && "unknown overrideable linkage" );
    147                                         } // if
    148                                 }
    149                                 isTopLevel = wasTopLevel;
    150                         }
    151 
    152                         void Mangler_old::postvisit( const ObjectDecl * declaration ) {
    153                                 mangleDecl( declaration );
    154                         }
    155 
    156                         void Mangler_old::postvisit( const FunctionDecl * declaration ) {
    157                                 mangleDecl( declaration );
    158                         }
    159 
    160                         void Mangler_old::postvisit( const VoidType * voidType ) {
    161                                 printQualifiers( voidType );
    162                                 mangleName += Encoding::void_t;
    163                         }
    164 
    165                         void Mangler_old::postvisit( const BasicType * basicType ) {
    166                                 printQualifiers( basicType );
    167                                 assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
    168                                 mangleName += Encoding::basicTypes[ basicType->kind ];
    169                         }
    170 
    171                         void Mangler_old::postvisit( const PointerType * pointerType ) {
    172                                 printQualifiers( pointerType );
    173                                 // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
    174                                 if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer;
    175                                 maybeAccept( pointerType->base, *visitor );
    176                         }
    177 
    178                         void Mangler_old::postvisit( const ArrayType * arrayType ) {
    179                                 // TODO: encode dimension
    180                                 printQualifiers( arrayType );
    181                                 mangleName += Encoding::array + "0";
    182                                 maybeAccept( arrayType->base, *visitor );
    183                         }
    184 
    185                         void Mangler_old::postvisit( const ReferenceType * refType ) {
    186                                 // don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
    187                                 // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
    188                                 // by pretending every reference type is a function parameter.
    189                                 GuardValue( inFunctionType );
    190                                 inFunctionType = true;
    191                                 printQualifiers( refType );
    192                                 maybeAccept( refType->base, *visitor );
    193                         }
    194 
    195                         namespace {
    196                                 inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {
    197                                         std::list< Type* > ret;
    198                                         std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
    199                                                                         std::mem_fun( &DeclarationWithType::get_type ) );
    200                                         return ret;
    201                                 }
    202                         }
    203 
    204                         void Mangler_old::postvisit( const FunctionType * functionType ) {
    205                                 printQualifiers( functionType );
    206                                 mangleName += Encoding::function;
    207                                 // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
    208                                 // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
    209                                 // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different
    210                                 GuardValue( inFunctionType );
    211                                 inFunctionType = true;
    212                                 std::list< Type* > returnTypes = getTypes( functionType->returnVals );
    213                                 if (returnTypes.empty()) mangleName += Encoding::void_t;
    214                                 else acceptAll( returnTypes, *visitor );
    215                                 mangleName += "_";
    216                                 std::list< Type* > paramTypes = getTypes( functionType->parameters );
    217                                 acceptAll( paramTypes, *visitor );
    218                                 mangleName += "_";
    219                         }
    220 
    221                         void Mangler_old::mangleRef( const ReferenceToType * refType, std::string prefix ) {
    222                                 printQualifiers( refType );
    223 
    224                                 mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
    225 
    226                                 if ( mangleGenericParams ) {
    227                                         const std::list< Expression* > & params = refType->parameters;
    228                                         if ( ! params.empty() ) {
    229                                                 mangleName += "_";
    230                                                 for ( const Expression * param : params ) {
    231                                                         const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param );
    232                                                         assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
    233                                                         maybeAccept( paramType->type, *visitor );
    234                                                 }
    235                                                 mangleName += "_";
    236                                         }
    237                                 }
    238                         }
    239 
    240                         void Mangler_old::postvisit( const StructInstType * aggregateUseType ) {
    241                                 mangleRef( aggregateUseType, Encoding::struct_t );
    242                         }
    243 
    244                         void Mangler_old::postvisit( const UnionInstType * aggregateUseType ) {
    245                                 mangleRef( aggregateUseType, Encoding::union_t );
    246                         }
    247 
    248                         void Mangler_old::postvisit( const EnumInstType * aggregateUseType ) {
    249                                 mangleRef( aggregateUseType, Encoding::enum_t );
    250                         }
    251 
    252                         void Mangler_old::postvisit( const TypeInstType * typeInst ) {
    253                                 VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
    254                                 if ( varNum == varNums.end() ) {
    255                                         mangleRef( typeInst, Encoding::type );
    256                                 } else {
    257                                         printQualifiers( typeInst );
    258                                         // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
    259                                         //   forall(dtype T) void f(T);
    260                                         //   forall(dtype S) void f(S);
    261                                         // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
    262                                         // are first found and prefixing with the appropriate encoding for the type class.
    263                                         assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    264                                         mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    265                                 } // if
    266                         }
    267 
    268                         void Mangler_old::postvisit( const TraitInstType * inst ) {
    269                                 printQualifiers( inst );
    270                                 mangleName += std::to_string( inst->name.size() ) + inst->name;
    271                         }
    272 
    273                         void Mangler_old::postvisit( const TupleType * tupleType ) {
    274                                 printQualifiers( tupleType );
    275                                 mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
    276                                 acceptAll( tupleType->types, *visitor );
    277                         }
    278 
    279                         void Mangler_old::postvisit( const VarArgsType * varArgsType ) {
    280                                 printQualifiers( varArgsType );
    281                                 static const std::string vargs = "__builtin_va_list";
    282                                 mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
    283                         }
    284 
    285                         void Mangler_old::postvisit( const ZeroType * ) {
    286                                 mangleName += Encoding::zero;
    287                         }
    288 
    289                         void Mangler_old::postvisit( const OneType * ) {
    290                                 mangleName += Encoding::one;
    291                         }
    292 
    293                         void Mangler_old::postvisit( const QualifiedType * qualType ) {
    294                                 bool inqual = inQualifiedType;
    295                                 if (! inqual ) {
    296                                         // N marks the start of a qualified type
    297                                         inQualifiedType = true;
    298                                         mangleName += Encoding::qualifiedTypeStart;
    299                                 }
    300                                 maybeAccept( qualType->parent, *visitor );
    301                                 maybeAccept( qualType->child, *visitor );
    302                                 if ( ! inqual ) {
    303                                         // E marks the end of a qualified type
    304                                         inQualifiedType = false;
    305                                         mangleName += Encoding::qualifiedTypeEnd;
    306                                 }
    307                         }
    308 
    309                         void Mangler_old::postvisit( const TypeDecl * decl ) {
    310                                 // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
    311                                 // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
    312                                 // Note: The current scheme may already work correctly for this case, I have not thought about this deeply
    313                                 // and the case has not yet come up in practice. Alternatively, if not then this code can be removed
    314                                 // aside from the assert false.
    315                                 assertf( false, "Mangler_old should not visit typedecl: %s", toCString(decl));
    316                                 assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    317                                 mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
    318                         }
    319 
    320                         __attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
    321                                 for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
    322                                         os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
    323                                 } // for
    324                         }
    325 
    326                         void Mangler_old::printQualifiers( const Type * type ) {
    327                                 // skip if not including qualifiers
    328                                 if ( typeMode ) return;
    329                                 if ( ! type->forall.empty() ) {
    330                                         std::list< std::string > assertionNames;
    331                                         int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    332                                         mangleName += Encoding::forall;
    333                                         for ( const TypeDecl * i : type->forall ) {
    334                                                 switch ( i->kind ) {
    335                                                   case TypeDecl::Dtype:
    336                                                         dcount++;
    337                                                         break;
    338                                                   case TypeDecl::Ftype:
    339                                                         fcount++;
    340                                                         break;
    341                                                   case TypeDecl::Ttype:
    342                                                         vcount++;
    343                                                         break;
    344                                                   default:
    345                                                         assertf( false, "unimplemented kind for type variable %s", SymTab::Mangler::Encoding::typeVariables[i->kind].c_str() );
    346                                                 } // switch
    347                                                 varNums[ i->name ] = std::make_pair( nextVarNum, (int)i->kind );
    348                                                 for ( const DeclarationWithType * assert : i->assertions ) {
    349                                                         PassVisitor<Mangler_old> sub_mangler(
    350                                                                 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    351                                                         assert->accept( sub_mangler );
    352                                                         assertionNames.push_back( sub_mangler.pass.get_mangleName() );
    353                                                         acount++;
    354                                                 } // for
    355                                         } // for
    356                                         mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
    357                                         for(const auto & a : assertionNames) mangleName += a;
    358 //                                      std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    359                                         mangleName += "_";
    360                                 } // if
    361                                 if ( ! inFunctionType ) {
    362                                         // these qualifiers do not distinguish the outermost type of a function parameter
    363                                         if ( type->get_const() ) {
    364                                                 mangleName += Encoding::qualifiers.at(Type::Const);
    365                                         } // if
    366                                         if ( type->get_volatile() ) {
    367                                                 mangleName += Encoding::qualifiers.at(Type::Volatile);
    368                                         } // if
    369                                         // Removed due to restrict not affecting function compatibility in GCC
    370                                         // if ( type->get_isRestrict() ) {
    371                                         //      mangleName += "E";
    372                                         // } // if
    373                                         if ( type->get_atomic() ) {
    374                                                 mangleName += Encoding::qualifiers.at(Type::Atomic);
    375                                         } // if
    376                                 }
    377                                 if ( type->get_mutex() ) {
    378                                         mangleName += Encoding::qualifiers.at(Type::Mutex);
    379                                 } // if
    380                                 if ( inFunctionType ) {
    381                                         // turn off inFunctionType so that types can be differentiated for nested qualifiers
    382                                         GuardValue( inFunctionType );
    383                                         inFunctionType = false;
    384                                 }
    385                         }
    386                 } // namespace
    387         } // namespace Mangler
    388 } // namespace SymTab
    38928
    39029namespace Mangle {
     
    476115                                mangleName += std::to_string( decl->name.size() ) + decl->name;
    477116                        } // if
    478                         maybeAccept( decl->get_type(), *visitor );
     117                        decl->get_type()->accept( *visitor );
    479118                        if ( mangleOverridable && decl->linkage.is_overrideable ) {
    480119                                // want to be able to override autogenerated and intrinsic routines,
     
    522161                        printQualifiers( arrayType );
    523162                        mangleName += Encoding::array + "0";
    524                         maybeAccept( arrayType->base.get(), *visitor );
     163                        arrayType->base->accept( *visitor );
    525164                }
    526165
     
    532171                        inFunctionType = true;
    533172                        printQualifiers( refType );
    534                         maybeAccept( refType->base.get(), *visitor );
     173                        refType->base->accept( *visitor );
    535174                }
    536175
     
    561200                                        auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
    562201                                        assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
    563                                         maybeAccept( paramType->type.get(), *visitor );
     202                                        paramType->type->accept( *visitor );
    564203                                }
    565204                                mangleName += "_";
     
    590229                                // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
    591230                                // are first found and prefixing with the appropriate encoding for the type class.
    592                                 assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
     231                                assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    593232                                mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    594233                        } // if
     
    622261                void Mangler_new::postvisit( const ast::QualifiedType * qualType ) {
    623262                        bool inqual = inQualifiedType;
    624                         if (! inqual ) {
     263                        if ( !inqual ) {
    625264                                // N marks the start of a qualified type
    626265                                inQualifiedType = true;
    627266                                mangleName += Encoding::qualifiedTypeStart;
    628267                        }
    629                         maybeAccept( qualType->parent.get(), *visitor );
    630                         maybeAccept( qualType->child.get(), *visitor );
    631                         if ( ! inqual ) {
     268                        qualType->parent->accept( *visitor );
     269                        qualType->child->accept( *visitor );
     270                        if ( !inqual ) {
    632271                                // E marks the end of a qualified type
    633272                                inQualifiedType = false;
     
    691330                                // these qualifiers do not distinguish the outermost type of a function parameter
    692331                                if ( type->is_const() ) {
    693                                         mangleName += Encoding::qualifiers.at(Type::Const);
     332                                        mangleName += Encoding::qualifiers.at( ast::CV::Const );
    694333                                } // if
    695334                                if ( type->is_volatile() ) {
    696                                         mangleName += Encoding::qualifiers.at(Type::Volatile);
     335                                        mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
    697336                                } // if
    698337                                // Removed due to restrict not affecting function compatibility in GCC
     
    701340                                // } // if
    702341                                if ( type->is_atomic() ) {
    703                                         mangleName += Encoding::qualifiers.at(Type::Atomic);
     342                                        mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
    704343                                } // if
    705344                        }
    706345                        if ( type->is_mutex() ) {
    707                                 mangleName += Encoding::qualifiers.at(Type::Mutex);
     346                                mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
    708347                        } // if
    709348                        if ( inFunctionType ) {
  • src/SymTab/Mangler.h

    r0030b508 rfc12f05  
    2222
    2323#include "AST/Bitfield.hpp"
    24 #include "SynTree/SynTree.h"  // for Types
    25 #include "SynTree/Visitor.h"  // for Visitor, maybeAccept
    2624
    2725// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
     
    3533        class Node;
    3634}
    37 namespace ResolvExpr {
    38         class TypeEnvironment;
    39 }
    4035
    4136namespace SymTab {
    4237        namespace Mangler {
    43                 /// Mangle syntax tree object; primary interface to clients
    44                 std::string mangle( const BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );
    45 
    46                 /// Mangle a type name; secondary interface
    47                 std::string mangleType( const Type * ty );
    48                 /// Mangle ignoring generic type parameters
    49                 std::string mangleConcrete( const Type * ty );
    50 
    5138                namespace Encoding {
    5239                        extern const std::string manglePrefix;
  • src/SymTab/ManglerCommon.cc

    r0030b508 rfc12f05  
    1515
    1616#include "Mangler.h"
    17 #include "SynTree/Type.h"
    18 #include "SynTree/Declaration.h"
     17
     18#include "AST/Decl.hpp"
     19#include "AST/Type.hpp"
    1920
    2021namespace SymTab {
     
    3940                        //   - "Di" char32_t
    4041                        //   - "Ds" char16_t
    41                         const std::string basicTypes[BasicType::NUMBER_OF_BASIC_TYPES] = {
     42                        const std::string basicTypes[ast::BasicType::NUMBER_OF_BASIC_TYPES] = {
    4243                                "b",        // _Bool
    4344                                "c",        // char
     
    7980                        // GENERATED END
    8081                        static_assert(
    81                                 sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
     82                                sizeof(basicTypes)/sizeof(basicTypes[0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES,
    8283                                "Each basic type kind should have a corresponding mangler letter"
    8384                        );
    8485
    8586                        const std::map<int, std::string> qualifiers = {
    86                                 { Type::Const, "K" },
    87                                 { Type::Volatile, "V" },
    88                                 { Type::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA
    89                                 { Type::Mutex, "X" },
     87                                { ast::CV::Const, "K" },
     88                                { ast::CV::Volatile, "V" },
     89                                { ast::CV::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA
     90                                { ast::CV::Mutex, "X" },
    9091                        };
    9192
     
    111112                        };
    112113                        static_assert(
    113                                 sizeof(typeVariables) / sizeof(typeVariables[0]) == TypeDecl::NUMBER_OF_KINDS,
     114                                sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
    114115                                "Each type variable kind should have a corresponding mangler prefix"
    115116                        );
  • src/SymTab/demangler.cc

    r0030b508 rfc12f05  
    22#include <iostream>
    33#include <fstream>
    4 using namespace std;
    54
    6 void f(const std::string & mangleName) {
     5void demangleAndPrint(const std::string & mangleName) {
    76        char * demangleName = cforall_demangle(mangleName.c_str(), 0);
    8         cout << mangleName << " => " << std::flush << demangleName << endl;
     7        std::cout << mangleName << " => " << demangleName << std::endl;
    98        free(demangleName);
    109}
    1110
    12 int main() {
    13         ifstream in("in-demangle.txt");
     11int main(int argc, char * argv[]) {
     12        char const * fileName = (1 < argc) ? argv[1] : "in-demangle.txt";
     13        std::ifstream in(fileName);
     14
    1415        std::string line;
    15         while (getline(in, line)) {
    16                 if (line.empty()) { cout << "=================================" << endl; continue; }
    17                 else if (line[0] == '#') continue;
    18                 f(line);
     16        while (std::getline(in, line)) {
     17                if (line.empty()) {
     18                        std::cout << "=================================" << std::endl;
     19                } else if (line[0] == '#') {
     20                        continue;
     21                } else {
     22                        demangleAndPrint(line);
     23                }
    1924        }
    2025}
  • src/SymTab/module.mk

    r0030b508 rfc12f05  
    1616
    1717SRC_SYMTAB = \
    18         SymTab/Autogen.cc \
    19         SymTab/Autogen.h \
    2018        SymTab/FixFunction.cc \
    2119        SymTab/FixFunction.h \
    2220        SymTab/GenImplicitCall.cpp \
    2321        SymTab/GenImplicitCall.hpp \
    24         SymTab/Indexer.cc \
    25         SymTab/Indexer.h \
    2622        SymTab/Mangler.cc \
    2723        SymTab/ManglerCommon.cc \
    28         SymTab/Mangler.h \
    29         SymTab/ValidateType.cc \
    30         SymTab/ValidateType.h
     24        SymTab/Mangler.h
    3125
    32 SRC += $(SRC_SYMTAB) \
    33         SymTab/Validate.cc \
    34         SymTab/Validate.h
     26SRC += $(SRC_SYMTAB)
    3527
    3628SRCDEMANGLE += $(SRC_SYMTAB) \
  • src/Tuples/Explode.cc

    r0030b508 rfc12f05  
    1515
    1616#include "Explode.h"
    17 #include <list>                  // for list
    1817
    1918#include "AST/Pass.hpp"          // for Pass
    20 #include "SynTree/Mutator.h"     // for Mutator
    21 #include "Common/PassVisitor.h"  // for PassVisitor
    2219
    2320namespace Tuples {
    24         namespace {
    25                 // remove one level of reference from a reference type -- may be useful elsewhere.
    26                 Type * getReferenceBase( Type * t ) {
    27                         if ( ReferenceType * refType = dynamic_cast<ReferenceType *>( t ) ) {
    28                                 return refType->get_base();
    29                         } else {
    30                                 // for the moment, I want to know immediately if a non-reference type is ever passed in here.
    31                                 assertf( false, "getReferenceBase for non-ref: %s", toString( refType ).c_str() );
    32                                 return nullptr;
    33                         }
    34                 }
    35 
    36                 struct CastExploder {
    37                         bool castAdded = false;
    38                         bool foundUniqueExpr = false;
    39                         Expression * applyCast( Expression * expr, bool first = true ) {
    40                                 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ){
    41                                         foundUniqueExpr = true;
    42                                         std::list< Expression * > exprs;
    43                                         for ( Expression *& expr : tupleExpr->get_exprs() ) {
    44                                                 // move cast into tuple exprs
    45                                                 exprs.push_back( applyCast( expr, false ) );
    46                                         }
    47                                         // want the top-level expression to be cast to reference type, but not nested
    48                                         // tuple expressions
    49                                         if ( first ) {
    50                                                 castAdded = true;
    51                                                 Expression * tupleExpr = new TupleExpr( exprs );
    52                                                 return new CastExpr( tupleExpr, new ReferenceType( Type::Qualifiers(), tupleExpr->result->clone() ) );
    53                                         } else {
    54                                                 return new TupleExpr( exprs );
    55                                         }
    56                                 }
    57                                 if ( dynamic_cast<ReferenceType*>( expr->result ) ) {
    58                                         // don't need to cast reference type to another reference type
    59                                         return expr->clone();
    60                                 } else {
    61                                         // anything else should be cast to reference as normal
    62                                         castAdded = true;
    63                                         return new CastExpr( expr->clone(), new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );
    64                                 }
    65                         }
    66 
    67                         Expression * postmutate( UniqueExpr * uniqueExpr ) {
    68                                 // move cast into unique expr so that the unique expr has type T& rather than
    69                                 // type T. In particular, this transformation helps with generating the
    70                                 // correct code for reference-cast member tuple expressions, since the result
    71                                 // should now be a tuple of references rather than a reference to a tuple.
    72                                 // Still, this code is a bit awkward, and could use some improvement.
    73                                 UniqueExpr * newUniqueExpr = new UniqueExpr( applyCast( uniqueExpr->get_expr() ), uniqueExpr->get_id() );
    74                                 delete uniqueExpr;
    75                                 if ( castAdded ) {
    76                                         // if a cast was added by applyCast, then unique expr now has one more layer of reference
    77                                         // than it had coming into this function. To ensure types still match correctly, need to cast
    78                                         //  to reference base so that outer expressions are still correct.
    79                                         castAdded = false;
    80                                         Type * toType = getReferenceBase( newUniqueExpr->result );
    81                                         return new CastExpr( newUniqueExpr, toType->clone() );
    82                                 }
    83                                 return newUniqueExpr;
    84                         }
    85 
    86 
    87                         Expression * postmutate( TupleIndexExpr * tupleExpr ) {
    88                                 // tuple index expr needs to be rebuilt to ensure that the type of the
    89                                 // field is consistent with the type of the tuple expr, since the field
    90                                 // may have changed from type T to T&.
    91                                 Expression * expr = tupleExpr->get_tuple();
    92                                 tupleExpr->set_tuple( nullptr );
    93                                 TupleIndexExpr * ret = new TupleIndexExpr( expr, tupleExpr->get_index() );
    94                                 delete tupleExpr;
    95                                 return ret;
    96                         }
    97                 };
    98         } // namespace
    99 
    100         Expression * distributeReference( Expression * expr ) {
    101                 PassVisitor<CastExploder> exploder;
    102                 expr = expr->acceptMutator( exploder );
    103                 if ( ! exploder.pass.foundUniqueExpr ) {
    104                         // if a UniqueExpr was found, then the cast has already been added inside the UniqueExpr as appropriate
    105                         expr = new CastExpr( expr, new ReferenceType( Type::Qualifiers(), expr->result->clone() ) );
    106                 }
    107                 return expr;
    108         }
    10921
    11022namespace {
  • src/Tuples/Explode.h

    r0030b508 rfc12f05  
    2020
    2121#include "AST/Expr.hpp"
    22 #include "ResolvExpr/Alternative.h"     // for Alternative, AltList
    2322#include "ResolvExpr/Candidate.hpp"     // for Candidate, CandidateList
    24 #include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
    2523#include "ResolvExpr/ExplodedArg.hpp"   // for ExplodedArg
    26 #include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
    27 #include "SynTree/Type.h"               // for TupleType, Type
    2824#include "Tuples.h"                     // for maybeImpure
    2925
     
    3228}
    3329
    34 namespace SymTab {
    35 class Indexer;
    36 }  // namespace SymTab
    37 
    3830namespace Tuples {
    39         Expression * distributeReference( Expression * );
    40 
    41         static inline CastExpr * isReferenceCast( Expression * expr ) {
    42                 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    43                         if ( dynamic_cast< ReferenceType * >( castExpr->result ) ) {
    44                                 return castExpr;
    45                         }
    46                 }
    47                 return nullptr;
    48         }
    49 
    50         /// Append alternative to an OutputIterator of Alternatives
    51         template<typename OutputIterator>
    52         void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,
    53                         const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,
    54                         const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {
    55                 *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };
    56         }
    57 
    58         /// Append alternative to an ExplodedActual
    59         static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,
    60                         const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,
    61                         const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
    62                 ea.exprs.emplace_back( expr );
    63                 /// xxx -- merge environment, openVars, need, cost?
    64         }
    65 
    66         /// helper function used by explode
    67         template< typename Output >
    68         void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt,
    69                         const SymTab::Indexer & indexer, Output&& out, bool isTupleAssign ) {
    70                 if ( isTupleAssign ) {
    71                         // tuple assignment needs CastExprs to be recursively exploded to easily get at all of the components
    72                         if ( CastExpr * castExpr = isReferenceCast( expr ) ) {
    73                                 ResolvExpr::AltList alts;
    74                                 explodeUnique(
    75                                         castExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );
    76                                 for ( ResolvExpr::Alternative & alt : alts ) {
    77                                         // distribute reference cast over all components
    78                                         append( std::forward<Output>(out), distributeReference( alt.release_expr() ),
    79                                                 alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );
    80                                 }
    81                                 // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)
    82                                 return;
    83                         }
    84                 }
    85                 Type * res = expr->get_result()->stripReferences();
    86                 if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
    87                         if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
    88                                 // can open tuple expr and dump its exploded components
    89                                 for ( Expression * expr : tupleExpr->get_exprs() ) {
    90                                         explodeUnique( expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
    91                                 }
    92                         } else {
    93                                 // tuple type, but not tuple expr - recursively index into its components.
    94                                 // if expr type is reference, convert to value type
    95                                 Expression * arg = expr->clone();
    96                                 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    97                                         // expressions which may contain side effects require a single unique instance of the expression.
    98                                         arg = new UniqueExpr( arg );
    99                                 }
    100                                 // cast reference to value type to facilitate further explosion
    101                                 if ( dynamic_cast<ReferenceType *>( arg->get_result() ) ) {
    102                                         arg = new CastExpr( arg, tupleType->clone() );
    103                                 }
    104                                 for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
    105                                         TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );
    106                                         explodeUnique( idx, alt, indexer, std::forward<Output>(out), isTupleAssign );
    107                                         delete idx;
    108                                 }
    109                                 delete arg;
    110                         }
    111                 } else {
    112                         // atomic (non-tuple) type - output a clone of the expression in a new alternative
    113                         append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need,
    114                                 alt.cost, alt.cvtCost );
    115                 }
    116         }
    117 
    118         /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
    119         template< typename Output >
    120         void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer,
    121                         Output&& out, bool isTupleAssign = false ) {
    122                 explodeUnique( alt.expr, alt, indexer, std::forward<Output>(out), isTupleAssign );
    123         }
    124 
    125         // explode list of alternatives
    126         template< typename AltIterator, typename Output >
    127         void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer,
    128                         Output&& out, bool isTupleAssign = false ) {
    129                 for ( ; altBegin != altEnd; ++altBegin ) {
    130                         explode( *altBegin, indexer, std::forward<Output>(out), isTupleAssign );
    131                 }
    132         }
    133 
    134         template< typename Output >
    135         void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, Output&& out,
    136                         bool isTupleAssign = false ) {
    137                 explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );
    138         }
    13931
    14032const ast::Expr * distributeReference( const ast::Expr * );
  • src/Tuples/TupleAssignment.cc

    r0030b508 rfc12f05  
    2828#include "AST/TypeEnvironment.hpp"
    2929#include "CodeGen/OperatorTable.h"
    30 #include "Common/PassVisitor.h"
    3130#include "Common/UniqueName.h"             // for UniqueName
    3231#include "Common/utility.h"                // for splice, zipWith
     
    3433#include "InitTweak/GenInit.h"             // for genCtorInit
    3534#include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
    36 #include "ResolvExpr/Alternative.h"        // for AltList, Alternative
    37 #include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
    3835#include "ResolvExpr/Cost.h"               // for Cost
    3936#include "ResolvExpr/Resolver.h"           // for resolveCtorInit
    40 #include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
    4137#include "ResolvExpr/typeops.h"            // for combos
    42 #include "SynTree/LinkageSpec.h"           // for Cforall
    43 #include "SynTree/Declaration.h"           // for ObjectDecl
    44 #include "SynTree/Expression.h"            // for Expression, CastExpr, Name...
    45 #include "SynTree/Initializer.h"           // for ConstructorInit, SingleInit
    46 #include "SynTree/Statement.h"             // for ExprStmt
    47 #include "SynTree/Type.h"                  // for Type, Type::Qualifiers
    48 #include "SynTree/TypeSubstitution.h"      // for TypeSubstitution
    49 #include "SynTree/Visitor.h"               // for Visitor
    5038
    5139#if 0
     
    5644
    5745namespace Tuples {
    58         class TupleAssignSpotter_old {
    59           public:
    60                 // dispatcher for Tuple (multiple and mass) assignment operations
    61                 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );
    62                 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
    63 
    64           private:
    65                 void match();
    66 
    67                 struct Matcher {
    68                   public:
    69                         Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    70                                 const ResolvExpr::AltList& rhs );
    71                         virtual ~Matcher() {}
    72 
    73                         virtual void match( std::list< Expression * > &out ) = 0;
    74                         ObjectDecl * newObject( UniqueName & namer, Expression * expr );
    75 
    76                         void combineState( const ResolvExpr::Alternative& alt ) {
    77                                 compositeEnv.simpleCombine( alt.env );
    78                                 ResolvExpr::mergeOpenVars( openVars, alt.openVars );
    79                                 cloneAll( alt.need, need );
    80                         }
    81 
    82                         void combineState( const ResolvExpr::AltList& alts ) {
    83                                 for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }
    84                         }
    85 
    86                         ResolvExpr::AltList lhs, rhs;
    87                         TupleAssignSpotter_old &spotter;
    88                         ResolvExpr::Cost baseCost;
    89                         std::list< ObjectDecl * > tmpDecls;
    90                         ResolvExpr::TypeEnvironment compositeEnv;
    91                         ResolvExpr::OpenVarSet openVars;
    92                         ResolvExpr::AssertionSet need;
    93                 };
    94 
    95                 struct MassAssignMatcher : public Matcher {
    96                   public:
    97                         MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    98                                 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    99                         virtual void match( std::list< Expression * > &out );
    100                 };
    101 
    102                 struct MultipleAssignMatcher : public Matcher {
    103                   public:
    104                         MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    105                                 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    106                         virtual void match( std::list< Expression * > &out );
    107                 };
    108 
    109                 ResolvExpr::AlternativeFinder &currentFinder;
    110                 std::string fname;
    111                 std::unique_ptr< Matcher > matcher;
    112         };
    113 
    114         /// true if expr is an expression of tuple type
    115         bool isTuple( Expression *expr ) {
    116                 if ( ! expr ) return false;
    117                 assert( expr->result );
    118                 return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );
    119         }
    120 
    121         template< typename AltIter >
    122         bool isMultAssign( AltIter begin, AltIter end ) {
    123                 // multiple assignment if more than one alternative in the range or if
    124                 // the alternative is a tuple
    125                 if ( begin == end ) return false;
    126                 if ( isTuple( begin->expr ) ) return true;
    127                 return ++begin != end;
    128         }
    129 
    130         bool refToTuple( Expression *expr ) {
    131                 assert( expr->get_result() );
    132                 // also check for function returning tuple of reference types
    133                 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    134                         return refToTuple( castExpr->get_arg() );
    135                 } else {
    136                         return isTuple( expr );
    137                 }
    138                 return false;
    139         }
    140 
    141         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
    142                                 std::vector<ResolvExpr::AlternativeFinder> &args ) {
    143                 TupleAssignSpotter_old spotter( currentFinder );
    144                 spotter.spot( expr, args );
    145         }
    146 
    147         TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
    148                 : currentFinder(f) {}
    149 
    150         void TupleAssignSpotter_old::spot( UntypedExpr * expr,
    151                         std::vector<ResolvExpr::AlternativeFinder> &args ) {
    152                 if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
    153                         if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {
    154                                 fname = op->get_name();
    155 
    156                                 // AlternativeFinder will naturally handle this case case, if it's legal
    157                                 if ( args.size() == 0 ) return;
    158 
    159                                 // if an assignment only takes 1 argument, that's odd, but maybe someone wrote
    160                                 // the function, in which case AlternativeFinder will handle it normally
    161                                 if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;
    162 
    163                                 // look over all possible left-hand-sides
    164                                 for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {
    165                                         // skip non-tuple LHS
    166                                         if ( ! refToTuple(lhsAlt.expr) ) continue;
    167 
    168                                         // explode is aware of casts - ensure every LHS expression is sent into explode
    169                                         // with a reference cast
    170                                         // xxx - this seems to change the alternatives before the normal
    171                                         //  AlternativeFinder flow; maybe this is desired?
    172                                         if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {
    173                                                 lhsAlt.expr = new CastExpr( lhsAlt.expr,
    174                                                                 new ReferenceType( Type::Qualifiers(),
    175                                                                         lhsAlt.expr->result->clone() ) );
    176                                         }
    177 
    178                                         // explode the LHS so that each field of a tuple-valued-expr is assigned
    179                                         ResolvExpr::AltList lhs;
    180                                         explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );
    181                                         for ( ResolvExpr::Alternative& alt : lhs ) {
    182                                                 // each LHS value must be a reference - some come in with a cast expression,
    183                                                 // if not just cast to reference here
    184                                                 if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {
    185                                                         alt.expr = new CastExpr( alt.expr,
    186                                                                 new ReferenceType( Type::Qualifiers(),
    187                                                                         alt.expr->get_result()->clone() ) );
    188                                                 }
    189                                         }
    190 
    191                                         if ( args.size() == 1 ) {
    192                                                 // mass default-initialization/destruction
    193                                                 ResolvExpr::AltList rhs{};
    194                                                 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
    195                                                 match();
    196                                         } else if ( args.size() > 2 ) {
    197                                                 // expand all possible RHS possibilities
    198                                                 // TODO build iterative version of this instead of using combos
    199                                                 std::vector< ResolvExpr::AltList > rhsAlts;
    200                                                 combos( std::next(args.begin(), 1), args.end(),
    201                                                         std::back_inserter( rhsAlts ) );
    202                                                 for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {
    203                                                         // multiple assignment
    204                                                         ResolvExpr::AltList rhs;
    205                                                         explode( rhsAlt, currentFinder.get_indexer(),
    206                                                                 std::back_inserter(rhs), true );
    207                                                         matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
    208                                                         match();
    209                                                 }
    210                                         } else {
    211                                                 for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {
    212                                                         ResolvExpr::AltList rhs;
    213                                                         if ( isTuple(rhsAlt.expr) ) {
    214                                                                 // multiple assignment
    215                                                                 explode( rhsAlt, currentFinder.get_indexer(),
    216                                                                         std::back_inserter(rhs), true );
    217                                                                 matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
    218                                                         } else {
    219                                                                 // mass assignment
    220                                                                 rhs.push_back( rhsAlt );
    221                                                                 matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
    222                                                         }
    223                                                         match();
    224                                                 }
    225                                         }
    226                                 }
    227                         }
    228                 }
    229         }
    230 
    231         void TupleAssignSpotter_old::match() {
    232                 assert ( matcher != 0 );
    233 
    234                 std::list< Expression * > new_assigns;
    235                 matcher->match( new_assigns );
    236 
    237                 if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {
    238                         // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.
    239                         // if not the empty tuple case, return early so that no new alternatives are generated.
    240                         if ( new_assigns.empty() ) return;
    241                 }
    242                 ResolvExpr::AltList current;
    243                 // now resolve new assignments
    244                 for ( std::list< Expression * >::iterator i = new_assigns.begin();
    245                                 i != new_assigns.end(); ++i ) {
    246                         PRINT(
    247                                 std::cerr << "== resolving tuple assign ==" << std::endl;
    248                                 std::cerr << *i << std::endl;
    249                         )
    250 
    251                         ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),
    252                                 matcher->compositeEnv };
    253 
    254                         try {
    255                                 finder.findWithAdjustment(*i);
    256                         } catch (...) {
    257                                 return; // no match should not mean failure, it just means this particular tuple assignment isn't valid
    258                         }
    259                         // prune expressions that don't coincide with
    260                         ResolvExpr::AltList alts = finder.get_alternatives();
    261                         assert( alts.size() == 1 );
    262                         assert( alts.front().expr != 0 );
    263                         current.push_back( alts.front() );
    264                 }
    265 
    266                 // extract expressions from the assignment alternatives to produce a list of assignments
    267                 // that together form a single alternative
    268                 std::list< Expression *> solved_assigns;
    269                 for ( ResolvExpr::Alternative & alt : current ) {
    270                         solved_assigns.push_back( alt.expr->clone() );
    271                         matcher->combineState( alt );
    272                 }
    273 
    274                 // xxx -- was push_front
    275                 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{
    276                         new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,
    277                         matcher->openVars,
    278                         ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),
    279                         ResolvExpr::sumCost( current ) + matcher->baseCost } );
    280         }
    281 
    282         TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,
    283                 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
    284         : lhs(lhs), rhs(rhs), spotter(spotter),
    285           baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {
    286                 combineState( lhs );
    287                 combineState( rhs );
    288         }
    289 
    290         UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
    291                 assert( left );
    292                 std::list< Expression * > args;
    293                 args.push_back( new VariableExpr( left ) );
    294                 // args.push_back( new AddressExpr( new VariableExpr( left ) ) );
    295                 if ( right ) args.push_back( new VariableExpr( right ) );
    296                 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
    297                         args.front() = new AddressExpr( args.front() );
    298                         if ( right ) args.back() = new AddressExpr( args.back() );
    299                         return new UntypedExpr( new NameExpr( "?=?" ), args );
    300                 } else {
    301                         return new UntypedExpr( new NameExpr( fname ), args );
    302                 }
    303         }
    304 
    305         // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv
    306         // xxx - maybe this should happen in alternative finder for every StmtExpr?
    307         struct EnvRemover {
    308                 void previsit( ExprStmt * stmt ) {
    309                         assert( compositeEnv );
    310                         if ( stmt->expr->env ) {
    311                                 compositeEnv->add( *stmt->expr->env );
    312                                 delete stmt->expr->env;
    313                                 stmt->expr->env = nullptr;
    314                         }
    315                 }
    316 
    317                 ResolvExpr::TypeEnvironment * compositeEnv = nullptr;
    318         };
    319 
    320         ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
    321                 assert( expr->result && ! expr->get_result()->isVoid() );
    322                 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
    323                 // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
    324                 if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {
    325                         ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
    326                         ret->init = ctorInit;
    327                         ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
    328                         PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs
    329                         rm.pass.compositeEnv = &compositeEnv;
    330                         ctorInit->accept( rm );
    331                 }
    332                 PRINT( std::cerr << "new object: " << ret << std::endl; )
    333                 return ret;
    334         }
    335 
    336         void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
    337                 static UniqueName lhsNamer( "__massassign_L" );
    338                 static UniqueName rhsNamer( "__massassign_R" );
    339                 // empty tuple case falls into this matcher, hence the second part of the assert
    340                 assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
    341 
    342                 // xxx - may need to split this up into multiple declarations, because potential conversion to references
    343                 //  probably should not reference local variable - see MultipleAssignMatcher::match
    344                 ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
    345                 for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
    346                         // create a temporary object for each value in the lhs and create a call involving the rhs
    347                         ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
    348                         out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
    349                         tmpDecls.push_back( ltmp );
    350                 }
    351                 if ( rtmp ) tmpDecls.push_back( rtmp );
    352         }
    353 
    354         void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
    355                 static UniqueName lhsNamer( "__multassign_L" );
    356                 static UniqueName rhsNamer( "__multassign_R" );
    357 
    358                 if ( lhs.size() == rhs.size() ) {
    359                         // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls
    360                         std::list< ObjectDecl * > ltmp;
    361                         std::list< ObjectDecl * > rtmp;
    362                         for ( auto p : group_iterate( lhs, rhs ) ) {
    363                                 ResolvExpr::Alternative & lhsAlt = std::get<0>(p);
    364                                 ResolvExpr::Alternative & rhsAlt = std::get<1>(p);
    365                                 // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.
    366                                 ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );
    367                                 rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );
    368                                 ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );
    369                                 ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );
    370                                 out.push_back( createFunc(spotter.fname, lobj, robj) );
    371                                 ltmp.push_back( lobj );
    372                                 rtmp.push_back( robj );
    373 
    374                                 // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment
    375                                 ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };
    376                                 finder.findWithAdjustment( rhsAlt.expr );
    377                                 assert( finder.get_alternatives().size() == 1 );
    378                                 compositeEnv = std::move( finder.get_alternatives().front().env );
    379                         }
    380                         tmpDecls.splice( tmpDecls.end(), ltmp );
    381                         tmpDecls.splice( tmpDecls.end(), rtmp );
    382                 }
    383         }
    38446
    38547namespace {
  • src/Tuples/TupleExpansion.cc

    r0030b508 rfc12f05  
    2323#include "AST/Node.hpp"
    2424#include "AST/Type.hpp"
    25 #include "Common/PassVisitor.h"   // for PassVisitor, WithDeclsToAdd, WithGu...
    2625#include "Common/ScopedMap.h"     // for ScopedMap
    2726#include "Common/utility.h"       // for CodeLocation
    2827#include "InitTweak/InitTweak.h"  // for getFunction
    29 #include "SynTree/LinkageSpec.h"  // for Spec, C, Intrinsic
    30 #include "SynTree/Constant.h"     // for Constant
    31 #include "SynTree/Declaration.h"  // for StructDecl, DeclarationWithType
    32 #include "SynTree/Expression.h"   // for UntypedMemberExpr, Expression, Uniq...
    33 #include "SynTree/Label.h"        // for operator==, Label
    34 #include "SynTree/Mutator.h"      // for Mutator
    35 #include "SynTree/Type.h"         // for Type, Type::Qualifiers, TupleType
    36 #include "SynTree/Visitor.h"      // for Visitor
    3728#include "Tuples.h"
    3829
    39 class CompoundStmt;
    40 class TypeSubstitution;
     30namespace Tuples {
    4131
    42 namespace Tuples {
    43         namespace {
    44                 struct MemberTupleExpander final : public WithShortCircuiting, public WithVisitorRef<MemberTupleExpander> {
    45                         void premutate( UntypedMemberExpr * ) { visit_children = false; }
    46                         Expression * postmutate( UntypedMemberExpr * memberExpr );
    47                 };
    48 
    49                 struct UniqueExprExpander final : public WithDeclsToAdd {
    50                         Expression * postmutate( UniqueExpr * unqExpr );
    51 
    52                         std::map< int, Expression * > decls; // not vector, because order added may not be increasing order
    53 
    54                         ~UniqueExprExpander() {
    55                                 for ( std::pair<const int, Expression *> & p : decls ) {
    56                                         delete p.second;
    57                                 }
    58                         }
    59                 };
    60 
    61                 struct TupleAssignExpander {
    62                         Expression * postmutate( TupleAssignExpr * tupleExpr );
    63                 };
    64 
    65                 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {
    66                         Type * postmutate( TupleType * tupleType );
    67 
    68                         void premutate( CompoundStmt * ) {
    69                                 GuardScope( typeMap );
    70                         }
    71                   private:
    72                         ScopedMap< int, StructDecl * > typeMap;
    73                 };
    74 
    75                 struct TupleIndexExpander {
    76                         Expression * postmutate( TupleIndexExpr * tupleExpr );
    77                 };
    78 
    79                 struct TupleExprExpander final {
    80                         Expression * postmutate( TupleExpr * tupleExpr );
    81                 };
    82         }
    83 
    84         void expandMemberTuples( std::list< Declaration * > & translationUnit ) {
    85                 PassVisitor<MemberTupleExpander> expander;
    86                 mutateAll( translationUnit, expander );
    87         }
    88 
    89         void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {
    90                 PassVisitor<UniqueExprExpander> unqExpander;
    91                 mutateAll( translationUnit, unqExpander );
    92         }
    93 
    94         void expandTuples( std::list< Declaration * > & translationUnit ) {
    95                 PassVisitor<TupleAssignExpander> assnExpander;
    96                 mutateAll( translationUnit, assnExpander );
    97 
    98                 PassVisitor<TupleTypeReplacer> replacer;
    99                 mutateAll( translationUnit, replacer );
    100 
    101                 PassVisitor<TupleIndexExpander> idxExpander;
    102                 mutateAll( translationUnit, idxExpander );
    103 
    104                 PassVisitor<TupleExprExpander> exprExpander;
    105                 mutateAll( translationUnit, exprExpander );
    106         }
    107 
    108         namespace {
    109                 /// given a expression representing the member and an expression representing the aggregate,
    110                 /// reconstructs a flattened UntypedMemberExpr with the right precedence
    111                 Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) {
    112                         if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {
    113                                 // construct a new UntypedMemberExpr with the correct structure , and recursively
    114                                 // expand that member expression.
    115                                 PassVisitor<MemberTupleExpander> expander;
    116                                 UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->aggregate, aggr->clone() );
    117                                 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member, inner );
    118                                 inner->location = newMemberExpr->location = loc;
    119                                 memberExpr->member = nullptr;
    120                                 memberExpr->aggregate = nullptr;
    121                                 delete memberExpr;
    122                                 return newMemberExpr->acceptMutator( expander );
    123                         } else {
    124                                 // not a member expression, so there is nothing to do but attach and return
    125                                 UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() );
    126                                 newMemberExpr->location = loc;
    127                                 return newMemberExpr;
    128                         }
    129                 }
    130         }
    131 
    132         Expression * MemberTupleExpander::postmutate( UntypedMemberExpr * memberExpr ) {
    133                 if ( UntypedTupleExpr * tupleExpr = dynamic_cast< UntypedTupleExpr * > ( memberExpr->member ) ) {
    134                         Expression * aggr = memberExpr->aggregate->clone()->acceptMutator( *visitor );
    135                         // aggregate expressions which might be impure must be wrapped in unique expressions
    136                         if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new UniqueExpr( aggr );
    137                         for ( Expression *& expr : tupleExpr->exprs ) {
    138                                 expr = reconstructMemberExpr( expr, aggr, memberExpr->location );
    139                                 expr->location = memberExpr->location;
    140                         }
    141                         delete aggr;
    142                         tupleExpr->location = memberExpr->location;
    143                         return tupleExpr;
    144                 } else {
    145                         // there may be a tuple expr buried in the aggregate
    146                         // xxx - this is a memory leak
    147                         UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->member->clone(), memberExpr->aggregate->acceptMutator( *visitor ) );
    148                         newMemberExpr->location = memberExpr->location;
    149                         return newMemberExpr;
    150                 }
    151         }
    152 
    153         Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) {
    154                 const int id = unqExpr->get_id();
    155 
    156                 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
    157                 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
    158                 if ( ! decls.count( id ) ) {
    159                         Expression * assignUnq;
    160                         Expression * var = unqExpr->get_var();
    161                         if ( unqExpr->get_object() ) {
    162                                 // an object was generated to represent this unique expression -- it should be added to the list of declarations now
    163                                 declsToAddBefore.push_back( unqExpr->get_object() );
    164                                 unqExpr->set_object( nullptr );
    165                                 // steal the expr from the unqExpr
    166                                 assignUnq = UntypedExpr::createAssign( unqExpr->get_var()->clone(), unqExpr->get_expr() );
    167                                 unqExpr->set_expr( nullptr );
    168                         } else {
    169                                 // steal the already generated assignment to var from the unqExpr - this has been generated by FixInit
    170                                 Expression * expr = unqExpr->get_expr();
    171                                 CommaExpr * commaExpr = strict_dynamic_cast< CommaExpr * >( expr );
    172                                 assignUnq = commaExpr->get_arg1();
    173                                 commaExpr->set_arg1( nullptr );
    174                         }
    175                         ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ),
    176                                                                                                         new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );
    177                         declsToAddBefore.push_back( finished );
    178                         // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
    179                         // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
    180                         Expression * assignFinished = UntypedExpr::createAssign( new VariableExpr(finished), new ConstantExpr( Constant::from_int( 1 ) ) );
    181                         ConditionalExpr * condExpr = new ConditionalExpr( new VariableExpr( finished ), var->clone(),
    182                                 new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );
    183                         condExpr->set_result( var->get_result()->clone() );
    184                         condExpr->set_env( maybeClone( unqExpr->get_env() ) );
    185                         decls[id] = condExpr;
    186                 }
    187                 delete unqExpr;
    188                 return decls[id]->clone();
    189         }
    190 
    191         Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) {
    192                 StmtExpr * ret = assnExpr->get_stmtExpr();
    193                 assnExpr->set_stmtExpr( nullptr );
    194                 // move env to StmtExpr
    195                 ret->set_env( assnExpr->get_env() );
    196                 assnExpr->set_env( nullptr );
    197                 delete assnExpr;
    198                 return ret;
    199         }
    200 
    201         Type * TupleTypeReplacer::postmutate( TupleType * tupleType ) {
    202                 unsigned tupleSize = tupleType->size();
    203                 if ( ! typeMap.count( tupleSize ) ) {
    204                         // generate struct type to replace tuple type based on the number of components in the tuple
    205                         StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) );
    206                         decl->location = tupleType->location;
    207                         decl->set_body( true );
    208                         for ( size_t i = 0; i < tupleSize; ++i ) {
    209                                 TypeDecl * tyParam = new TypeDecl( toString( "tuple_param_", tupleSize, "_", i ), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true );
    210                                 decl->get_members().push_back( new ObjectDecl( toString("field_", i ), Type::StorageClasses(), LinkageSpec::C, nullptr, new TypeInstType( Type::Qualifiers(), tyParam->get_name(), tyParam ), nullptr ) );
    211                                 decl->get_parameters().push_back( tyParam );
    212                         }
    213                         if ( tupleSize == 0 ) {
    214                                 // empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.
    215                                 decl->get_members().push_back( new ObjectDecl( "dummy", Type::StorageClasses(), LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
    216                         }
    217                         typeMap[tupleSize] = decl;
    218                         declsToAddBefore.push_back( decl );
    219                 }
    220                 Type::Qualifiers qualifiers = tupleType->get_qualifiers();
    221 
    222                 StructDecl * decl = typeMap[tupleSize];
    223                 StructInstType * newType = new StructInstType( qualifiers, decl );
    224                 for ( auto p : group_iterate( tupleType->get_types(), decl->get_parameters() ) ) {
    225                         Type * t = std::get<0>(p);
    226                         newType->get_parameters().push_back( new TypeExpr( t->clone() ) );
    227                 }
    228                 delete tupleType;
    229                 return newType;
    230         }
    231 
    232         Expression * TupleIndexExpander::postmutate( TupleIndexExpr * tupleExpr ) {
    233                 Expression * tuple = tupleExpr->tuple;
    234                 assert( tuple );
    235                 tupleExpr->tuple = nullptr;
    236                 unsigned int idx = tupleExpr->index;
    237                 TypeSubstitution * env = tupleExpr->env;
    238                 tupleExpr->env = nullptr;
    239                 delete tupleExpr;
    240 
    241                 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * > ( tuple ) ) {
    242                         if ( ! maybeImpureIgnoreUnique( tupleExpr ) ) {
    243                                 // optimization: definitely pure tuple expr => can reduce to the only relevant component.
    244                                 assert( tupleExpr->exprs.size() > idx );
    245                                 Expression *& expr = *std::next(tupleExpr->exprs.begin(), idx);
    246                                 Expression * ret = expr;
    247                                 ret->env = env;
    248                                 expr = nullptr; // remove from list so it can safely be deleted
    249                                 delete tupleExpr;
    250                                 return ret;
    251                         }
    252                 }
    253 
    254                 StructInstType * type = strict_dynamic_cast< StructInstType * >( tuple->result );
    255                 StructDecl * structDecl = type->baseStruct;
    256                 assert( structDecl->members.size() > idx );
    257                 Declaration * member = *std::next(structDecl->members.begin(), idx);
    258                 MemberExpr * memExpr = new MemberExpr( strict_dynamic_cast< DeclarationWithType * >( member ), tuple );
    259                 memExpr->env = env;
    260                 return memExpr;
    261         }
    262 
    263         Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) {
    264                 if ( result->isVoid() ) {
    265                         // void result - don't need to produce a value for cascading - just output a chain of comma exprs
    266                         assert( ! exprs.empty() );
    267                         std::list< Expression * >::const_iterator iter = exprs.begin();
    268                         Expression * expr = new CastExpr( *iter++ );
    269                         for ( ; iter != exprs.end(); ++iter ) {
    270                                 expr = new CommaExpr( expr, new CastExpr( *iter ) );
    271                         }
    272                         expr->set_env( env );
    273                         return expr;
    274                 } else {
    275                         // typed tuple expression - produce a compound literal which performs each of the expressions
    276                         // as a distinct part of its initializer - the produced compound literal may be used as part of
    277                         // another expression
    278                         std::list< Initializer * > inits;
    279                         for ( Expression * expr : exprs ) {
    280                                 inits.push_back( new SingleInit( expr ) );
    281                         }
    282                         Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) );
    283                         expr->set_env( env );
    284                         return expr;
    285                 }
    286         }
    287 
    288         Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) {
    289                 Type * result = tupleExpr->get_result();
    290                 std::list< Expression * > exprs = tupleExpr->get_exprs();
    291                 assert( result );
    292                 TypeSubstitution * env = tupleExpr->get_env();
    293 
    294                 // remove data from shell and delete it
    295                 tupleExpr->set_result( nullptr );
    296                 tupleExpr->get_exprs().clear();
    297                 tupleExpr->set_env( nullptr );
    298                 delete tupleExpr;
    299 
    300                 return replaceTupleExpr( result, exprs, env );
    301         }
    302 
    303         Type * makeTupleType( const std::list< Expression * > & exprs ) {
    304                 // produce the TupleType which aggregates the types of the exprs
    305                 std::list< Type * > types;
    306                 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex );
    307                 for ( Expression * expr : exprs ) {
    308                         assert( expr->get_result() );
    309                         if ( expr->get_result()->isVoid() ) {
    310                                 // if the type of any expr is void, the type of the entire tuple is void
    311                                 return new VoidType( Type::Qualifiers() );
    312                         }
    313                         Type * type = expr->get_result()->clone();
    314                         types.push_back( type );
    315                         // the qualifiers on the tuple type are the qualifiers that exist on all component types
    316                         qualifiers &= type->get_qualifiers();
    317                 } // for
    318                 if ( exprs.empty() ) qualifiers = Type::Qualifiers();
    319                 return new TupleType( qualifiers, types );
    320         }
    32132        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
    32233                // produce the TupleType which aggregates the types of the exprs
     
    34152        }
    34253
    343         TypeInstType * isTtype( Type * type ) {
    344                 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( type ) ) {
    345                         if ( inst->get_baseType() && inst->get_baseType()->get_kind() == TypeDecl::Ttype ) {
    346                                 return inst;
    347                         }
    348                 }
    349                 return nullptr;
    350         }
    351 
    352         const TypeInstType * isTtype( const Type * type ) {
    353                 if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) {
    354                         if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) {
    355                                 return inst;
    356                         }
    357                 }
    358                 return nullptr;
    359         }
    360 
    36154        const ast::TypeInstType * isTtype( const ast::Type * type ) {
    36255                if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
  • src/Tuples/Tuples.cc

    r0030b508 rfc12f05  
    1919#include "AST/Inspect.hpp"
    2020#include "AST/LinkageSpec.hpp"
    21 #include "Common/PassVisitor.h"
    2221#include "InitTweak/InitTweak.h"
    2322
     
    2524
    2625namespace {
    27         /// Checks if impurity (read: side-effects) may exist in a piece of code.
    28         /// Currently gives a very crude approximation, wherein any function
    29         /// call expression means the code may be impure.
    30         struct ImpurityDetector_old : public WithShortCircuiting {
    31                 bool const ignoreUnique;
    32                 bool maybeImpure;
    33 
    34                 ImpurityDetector_old( bool ignoreUnique ) :
    35                         ignoreUnique( ignoreUnique ), maybeImpure( false )
    36                 {}
    37 
    38                 void previsit( const ApplicationExpr * appExpr ) {
    39                         visit_children = false;
    40                         if ( const DeclarationWithType * function =
    41                                         InitTweak::getFunction( appExpr ) ) {
    42                                 if ( function->linkage == LinkageSpec::Intrinsic ) {
    43                                         if ( function->name == "*?" || function->name == "?[?]" ) {
    44                                                 // intrinsic dereference, subscript are pure,
    45                                                 // but need to recursively look for impurity
    46                                                 visit_children = true;
    47                                                 return;
    48                                         }
    49                                 }
    50                         }
    51                         maybeImpure = true;
    52                 }
    53 
    54                 void previsit( const UntypedExpr * ) {
    55                         maybeImpure = true;
    56                         visit_children = false;
    57                 }
    58 
    59                 void previsit( const UniqueExpr * ) {
    60                         if ( ignoreUnique ) {
    61                                 // bottom out at unique expression.
    62                                 // The existence of a unique expression doesn't change the purity of an expression.
    63                                 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
    64                                 visit_children = false;
    65                                 return;
    66                         }
    67                 }
    68         };
    69 
    70         bool detectImpurity( const Expression * expr, bool ignoreUnique ) {
    71                 PassVisitor<ImpurityDetector_old> detector( ignoreUnique );
    72                 expr->accept( detector );
    73                 return detector.pass.maybeImpure;
    74         }
    7526
    7627        /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives
     
    11061}
    11162
    112 bool maybeImpure( const Expression * expr ) {
    113         return detectImpurity( expr, false );
    114 }
    115 
    116 bool maybeImpureIgnoreUnique( const Expression * expr ) {
    117         return detectImpurity( expr, true );
    118 }
    119 
    12063} // namespace Tuples
    12164
  • src/Tuples/Tuples.h

    r0030b508 rfc12f05  
    2121#include "AST/Fwd.hpp"
    2222#include "AST/Node.hpp"
    23 #include "SynTree/Expression.h"
    24 #include "SynTree/Declaration.h"
    25 #include "SynTree/Type.h"
    26 
    27 #include "ResolvExpr/AlternativeFinder.h"
    2823#include "ResolvExpr/CandidateFinder.hpp"
    2924
    3025namespace Tuples {
    3126        // TupleAssignment.cc
    32         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
    33                 std::vector< ResolvExpr::AlternativeFinder >& args );
    3427        void handleTupleAssignment(
    3528                ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     
    3831        // TupleExpansion.cc
    3932        /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
    40         void expandMemberTuples( std::list< Declaration * > & translationUnit );
    4133        void expandMemberTuples( ast::TranslationUnit & translationUnit );
    4234
    4335        /// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
    44         void expandTuples( std::list< Declaration * > & translationUnit );
    4536        void expandTuples( ast::TranslationUnit & translaionUnit );
    4637
    4738        /// replaces UniqueExprs with a temporary variable and one call
    48         void expandUniqueExpr( std::list< Declaration * > & translationUnit );
    4939        void expandUniqueExpr( ast::TranslationUnit & translationUnit );
    5040
    5141        /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
    52         Type * makeTupleType( const std::list< Expression * > & exprs );
    5342        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
    5443
    5544        /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
    56         TypeInstType * isTtype( Type * type );
    57         const TypeInstType * isTtype( const Type * type );
    5845        const ast::TypeInstType * isTtype( const ast::Type * type );
    5946
    6047        /// returns true if the expression may contain side-effects.
    61         bool maybeImpure( const Expression * expr );
    6248        bool maybeImpure( const ast::Expr * expr );
    6349
    6450        /// Returns true if the expression may contain side-effect,
    6551        /// ignoring the presence of unique expressions.
    66         bool maybeImpureIgnoreUnique( const Expression * expr );
    6752        bool maybeImpureIgnoreUnique( const ast::Expr * expr );
    6853} // namespace Tuples
  • src/Validate/FindSpecialDecls.h

    r0030b508 rfc12f05  
    1616#pragma once
    1717
    18 #include <list>  // for list
    19 
    20 class Declaration;
    21 class FunctionDecl;
    22 class StructDecl;
    23 class Type;
    24 
    2518namespace ast {
    2619        class TranslationUnit;
     
    2821
    2922namespace Validate {
    30         /// size_t type - set when size_t typedef is seen. Useful in a few places,
    31         /// such as in determining array dimension type
    32         extern Type * SizeType;
    33 
    34         /// intrinsic dereference operator for unqualified types - set when *? function is seen in FindSpecialDeclarations.
    35         /// Useful for creating dereference ApplicationExprs without a full resolver pass.
    36         extern FunctionDecl * dereferenceOperator;
    37 
    38         /// special built-in functions and data structures necessary for destructor generation
    39         extern StructDecl * dtorStruct;
    40         extern FunctionDecl * dtorStructDestroy;
    41 
    42         /// find and remember some of the special declarations that are useful for generating code, so that they do not have to be discovered multiple times.
    43         void findSpecialDecls( std::list< Declaration * > & translationUnit );
    4423
    4524/// Find and remember some of the special declarations that are useful for
  • src/Validate/FixReturnTypes.cpp

    r0030b508 rfc12f05  
    1919#include "AST/Pass.hpp"
    2020#include "AST/Type.hpp"
    21 #include "CodeGen/CodeGenerator.h"
     21#include "CodeGen/CodeGeneratorNew.hpp"
    2222#include "ResolvExpr/Unify.h"
    2323
  • src/Validate/module.mk

    r0030b508 rfc12f05  
    1616
    1717SRC_VALIDATE = \
    18         Validate/FindSpecialDecls.cc \
    1918        Validate/FindSpecialDecls.h
    2019
     
    3736        Validate/GenericParameter.cpp \
    3837        Validate/GenericParameter.hpp \
    39         Validate/HandleAttributes.cc \
    40         Validate/HandleAttributes.h \
    4138        Validate/HoistStruct.cpp \
    4239        Validate/HoistStruct.hpp \
  • src/Virtual/ExpandCasts.cc

    r0030b508 rfc12f05  
    2424#include "AST/Expr.hpp"
    2525#include "AST/Pass.hpp"
    26 #include "Common/PassVisitor.h"    // for PassVisitor
    2726#include "Common/ScopedMap.h"      // for ScopedMap
    2827#include "Common/SemanticError.h"  // for SemanticError
    2928#include "SymTab/Mangler.h"        // for mangleType
    30 #include "SynTree/Declaration.h"   // for ObjectDecl, StructDecl, FunctionDecl
    31 #include "SynTree/Expression.h"    // for VirtualCastExpr, CastExpr, Address...
    32 #include "SynTree/Mutator.h"       // for mutateAll
    33 #include "SynTree/Type.h"          // for Type, PointerType, StructInstType
    34 #include "SynTree/Visitor.h"       // for acceptAll
    3529
    3630namespace Virtual {
     
    4337}
    4438
    45 bool is_type_id_object( const ObjectDecl * objectDecl ) {
    46         const std::string & objectName = objectDecl->name;
    47         return is_prefix( "__cfatid_", objectName );
    48 }
    49 
    5039bool is_type_id_object( const ast::ObjectDecl * decl ) {
    5140        return is_prefix( "__cfatid_", decl->name );
     
    5544
    5645        /// Maps virtual table types the instance for that type.
    57         class VirtualTableMap final {
    58                 ScopedMap<std::string, ObjectDecl *> vtable_instances;
    59         public:
    60                 void enterScope() {
    61                         vtable_instances.beginScope();
    62                 }
    63                 void leaveScope() {
    64                         vtable_instances.endScope();
    65                 }
    66 
    67                 ObjectDecl * insert( ObjectDecl * vtableDecl ) {
    68                         std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
    69                         ObjectDecl *& value = vtable_instances[ mangledName ];
    70                         if ( value ) {
    71                                 if ( vtableDecl->storageClasses.is_extern ) {
    72                                         return nullptr;
    73                                 } else if ( ! value->storageClasses.is_extern ) {
    74                                         return value;
    75                                 }
    76                         }
    77                         value = vtableDecl;
    78                         return nullptr;
    79                 }
    80 
    81                 ObjectDecl * lookup( const Type * vtableType ) {
    82                         std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
    83                         const auto it = vtable_instances.find( mangledName );
    84                         return ( vtable_instances.end() == it ) ? nullptr : it->second;
    85                 }
    86         };
    87 
    88         class VirtualCastCore {
    89                 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
    90                         Type * type = new StructInstType(
    91                                 Type::Qualifiers( Type::Const ), pvt_decl );
    92                         for (int i = 0 ; i < level_of_indirection ; ++i) {
    93                                 type = new PointerType( noQualifiers, type );
    94                         }
    95                         return new CastExpr( expr, type );
    96                 }
    97 
    98         public:
    99                 VirtualCastCore() :
    100                         indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )
    101                 {}
    102 
    103                 void premutate( FunctionDecl * functionDecl );
    104                 void premutate( StructDecl * structDecl );
    105                 void premutate( ObjectDecl * objectDecl );
    106 
    107                 Expression * postmutate( VirtualCastExpr * castExpr );
    108 
    109                 VirtualTableMap indexer;
    110         private:
    111                 FunctionDecl *vcast_decl;
    112                 StructDecl *pvt_decl;
    113         };
    114 
    115         void VirtualCastCore::premutate( FunctionDecl * functionDecl ) {
    116                 if ( (! vcast_decl) &&
    117                      functionDecl->get_name() == "__cfavir_virtual_cast" ) {
    118                         vcast_decl = functionDecl;
    119                 }
    120         }
    121 
    122         void VirtualCastCore::premutate( StructDecl * structDecl ) {
    123                 if ( pvt_decl || ! structDecl->has_body() ) {
    124                         return;
    125                 } else if ( structDecl->get_name() == "__cfavir_type_info" ) {
    126                         pvt_decl = structDecl;
    127                 }
    128         }
    129 
    130         void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
    131                 if ( is_type_id_object( objectDecl ) ) {
    132                         // Multiple definitions should be fine because of linkonce.
    133                         indexer.insert( objectDecl );
    134                 }
    135         }
    136 
    137         /// Better error locations for generated casts.
    138         CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
    139                 if ( castExpr->location.isSet() ) {
    140                         return castExpr->location;
    141                 } else if ( castExpr->arg->location.isSet() ) {
    142                         return castExpr->arg->location;
    143                 } else if ( castExpr->result->location.isSet() ) {
    144                         return castExpr->result->location;
    145                 } else {
    146                         return CodeLocation();
    147                 }
    148         }
    149 
    150         [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
    151                 SemanticError( castLocation( castExpr ), message );
    152         }
    153 
    154         /// Get the base type from a pointer or reference.
    155         const Type * getBaseType( const Type * type ) {
    156                 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
    157                         return target->base;
    158                 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
    159                         return target->base;
    160                 } else {
    161                         return nullptr;
    162                 }
    163         }
    164 
    165         /* Attempt to follow the "head" field of the structure to get the...
    166          * Returns nullptr on error, otherwise owner must free returned node.
    167          */
    168         StructInstType * followHeadPointerType(
    169                         const StructInstType * oldType,
    170                         const std::string& fieldName,
    171                         const CodeLocation& errorLocation ) {
    172 
    173                 // First section of the function is all about trying to fill this variable in.
    174                 StructInstType * newType = nullptr;
    175                 {
    176                         const StructDecl * oldDecl = oldType->baseStruct;
    177                         assert( oldDecl );
    178 
    179                         // Helper function for throwing semantic errors.
    180                         auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
    181                                 const std::string& context = "While following head pointer of " +
    182                                         oldDecl->name + " named '" + fieldName + "': ";
    183                                 SemanticError( errorLocation, context + message );
    184                         };
    185 
    186                         if ( oldDecl->members.empty() ) {
    187                                 throwError( "Type has no fields." );
    188                         }
    189                         const Declaration * memberDecl = oldDecl->members.front();
    190                         assert( memberDecl );
    191                         const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
    192                         assert( fieldDecl );
    193                         if ( fieldName != fieldDecl->name ) {
    194                                 throwError( "Head field did not have expected name." );
    195                         }
    196 
    197                         const Type * fieldType = fieldDecl->type;
    198                         if ( nullptr == fieldType ) {
    199                                 throwError( "Could not get head field." );
    200                         }
    201                         const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
    202                         if ( nullptr == ptrType ) {
    203                                 throwError( "First field is not a pointer type." );
    204                         }
    205                         assert( ptrType->base );
    206                         newType = dynamic_cast<StructInstType *>( ptrType->base );
    207                         if ( nullptr == newType ) {
    208                                 throwError( "First field does not point to a structure type." );
    209                         }
    210                 }
    211 
    212                 // Now we can look into copying it.
    213                 newType = newType->clone();
    214                 if ( ! oldType->parameters.empty() ) {
    215                         deleteAll( newType->parameters );
    216                         newType->parameters.clear();
    217                         cloneAll( oldType->parameters, newType->parameters );
    218                 }
    219                 return newType;
    220         }
    221 
    222         /// Get the type-id type from a virtual type.
    223         StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
    224                 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
    225                 if ( nullptr == typeInst ) {
    226                         return nullptr;
    227                 }
    228                 StructInstType * tableInst =
    229                         followHeadPointerType( typeInst, "virtual_table", errorLocation );
    230                 if ( nullptr == tableInst ) {
    231                         return nullptr;
    232                 }
    233                 StructInstType * typeIdInst =
    234                         followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
    235                 delete tableInst;
    236                 return typeIdInst;
    237         }
    238 
    239         Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
    240                 assertf( castExpr->result, "Virtual Cast target not found before expansion." );
    241 
    242                 assert( vcast_decl );
    243                 assert( pvt_decl );
    244 
    245                 const Type * base_type = getBaseType( castExpr->result );
    246                 if ( nullptr == base_type ) {
    247                         castError( castExpr, "Virtual cast target must be a pointer or reference type." );
    248                 }
    249                 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
    250                 if ( nullptr == type_id_type ) {
    251                         castError( castExpr, "Ill formed virtual cast target type." );
    252                 }
    253                 ObjectDecl * type_id = indexer.lookup( type_id_type );
    254                 delete type_id_type;
    255                 if ( nullptr == type_id ) {
    256                         castError( castExpr, "Virtual cast does not target a virtual type." );
    257                 }
    258 
    259                 Expression * result = new CastExpr(
    260                         new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    261                                 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
    262                                 cast_to_type_id( castExpr->get_arg(), 2 ),
    263                         } ),
    264                         castExpr->get_result()->clone()
    265                 );
    266 
    267                 castExpr->set_arg( nullptr );
    268                 castExpr->set_result( nullptr );
    269                 delete castExpr;
    270                 return result;
    271         }
    27246
    27347/// Better error locations for generated casts.
     
    494268} // namespace
    495269
    496 void expandCasts( std::list< Declaration * > & translationUnit ) {
    497         PassVisitor<VirtualCastCore> translator;
    498         mutateAll( translationUnit, translator );
    499 }
    500 
    501270void expandCasts( ast::TranslationUnit & translationUnit ) {
    502271        ast::Pass<ExpandCastsCore>::run( translationUnit );
  • src/Virtual/Tables.cc

    r0030b508 rfc12f05  
    2121#include "AST/Stmt.hpp"
    2222#include "AST/Type.hpp"
    23 #include <SynTree/Attribute.h>
    24 #include <SynTree/Declaration.h>
    25 #include <SynTree/Expression.h>
    26 #include <SynTree/Statement.h>
    27 #include <SynTree/Type.h>
    2823
    2924namespace Virtual {
     
    6560        return 17 < name.size() && '_' == name[0] &&
    6661                std::string("_vtable_instance") == name.substr(1, name.size() - 17);
    67 }
    68 
    69 static ObjectDecl * makeVtableDeclaration(
    70                 std::string const & name,
    71                 StructInstType * type, Initializer * init ) {
    72         Type::StorageClasses storage = noStorageClasses;
    73         if ( nullptr == init ) {
    74                 storage.is_extern = true;
    75         }
    76         return new ObjectDecl(
    77                 name,
    78                 storage,
    79                 LinkageSpec::Cforall,
    80                 nullptr,
    81                 type,
    82                 init
    83         );
    8462}
    8563
     
    10179}
    10280
    103 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {
    104         assert( type );
    105         return makeVtableDeclaration( name, type, nullptr );
    106 }
    107 
    10881ast::ObjectDecl * makeVtableForward(
    10982                CodeLocation const & location, std::string const & name,
     
    11184        assert( vtableType );
    11285        return makeVtableDeclaration( location, name, vtableType, nullptr );
    113 }
    114 
    115 ObjectDecl * makeVtableInstance(
    116                 std::string const & name, StructInstType * vtableType,
    117                 Type * objectType, Initializer * init ) {
    118         assert( vtableType );
    119         assert( objectType );
    120         StructDecl * vtableStruct = vtableType->baseStruct;
    121         // Build the initialization
    122         if ( nullptr == init ) {
    123                 std::list< Initializer * > inits;
    124 
    125                 // This is going to have to be run before the resolver to connect expressions.
    126                 for ( auto field : vtableStruct->members ) {
    127                         if ( std::string( "parent" ) == field->name ) {
    128                                 // This will not work with polymorphic state.
    129                                 auto oField = strict_dynamic_cast< ObjectDecl * >( field );
    130                                 auto fieldType = strict_dynamic_cast< PointerType * >( oField->type );
    131                                 auto parentType = strict_dynamic_cast< StructInstType * >( fieldType->base );
    132                                 std::string const & parentInstance = instanceName( parentType->name );
    133                                 inits.push_back(
    134                                                 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
    135                         } else if ( std::string( "__cfavir_typeid" ) == field->name ) {
    136                                 std::string const & baseType = baseTypeName( vtableType->name );
    137                                 std::string const & typeId = typeIdName( baseType );
    138                                 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );
    139                         } else if ( std::string( "size" ) == field->name ) {
    140                                 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
    141                         } else if ( std::string( "align" ) == field->name ) {
    142                                 inits.push_back( new SingleInit( new AlignofExpr( objectType->clone() ) ) );
    143                         } else {
    144                                 inits.push_back( new SingleInit( new NameExpr( field->name ) ) );
    145                         }
    146                 }
    147                 init = new ListInit( inits );
    148         // This should initialize everything except the parent pointer, the
    149         // size-of and align-of fields. These should be inserted.
    150         } else {
    151                 assert(false);
    152         }
    153         return makeVtableDeclaration( name, vtableType, init );
    15486}
    15587
     
    224156}
    225157
    226 FunctionDecl * makeGetExceptionForward(
    227                 Type * vtableType, Type * exceptType ) {
    228         assert( vtableType );
    229         assert( exceptType );
    230         FunctionType * type = new FunctionType( noQualifiers, false );
    231         vtableType->tq.is_const = true;
    232         type->returnVals.push_back( new ObjectDecl(
    233                 "_retvalue",
    234                 noStorageClasses,
    235                 LinkageSpec::Cforall,
    236                 nullptr,
    237                 new ReferenceType( noQualifiers, vtableType ),
    238                 nullptr,
    239                 { new Attribute("unused") }
    240         ) );
    241         type->parameters.push_back( new ObjectDecl(
    242                 "__unused",
    243                 noStorageClasses,
    244                 LinkageSpec::Cforall,
    245                 nullptr,
    246                 new PointerType( noQualifiers, exceptType ),
    247                 nullptr,
    248                 { new Attribute("unused") }
    249         ) );
    250         return new FunctionDecl(
    251                 functionName,
    252                 noStorageClasses,
    253                 LinkageSpec::Cforall,
    254                 type,
    255                 nullptr
    256         );
    257 }
    258 
    259158ast::FunctionDecl * makeGetExceptionForward(
    260159                CodeLocation const & location,
     
    284183}
    285184
    286 FunctionDecl * makeGetExceptionFunction(
    287                 ObjectDecl * vtableInstance, Type * exceptType ) {
    288         assert( vtableInstance );
    289         assert( exceptType );
    290         FunctionDecl * func = makeGetExceptionForward(
    291                 vtableInstance->type->clone(), exceptType );
    292         func->statements = new CompoundStmt( {
    293                 new ReturnStmt( new VariableExpr( vtableInstance ) ),
    294         } );
    295         return func;
    296 }
    297 
    298185ast::FunctionDecl * makeGetExceptionFunction(
    299186                CodeLocation const & location,
     
    307194        } );
    308195        return func;
    309 }
    310 
    311 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
    312         assert( typeIdType );
    313         StructInstType * type = typeIdType->clone();
    314         type->tq.is_const = true;
    315         std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
    316         return new ObjectDecl(
    317                 typeid_name,
    318                 noStorageClasses,
    319                 LinkageSpec::Cforall,
    320                 /* bitfieldWidth */ nullptr,
    321                 type,
    322                 new ListInit( { new SingleInit(
    323                         new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
    324                         ) } ),
    325                 { new Attribute( "cfa_linkonce", {} ) },
    326                 noFuncSpecifiers
    327         );
    328196}
    329197
  • src/Virtual/Tables.h

    r0030b508 rfc12f05  
    1818#include <string>
    1919#include "AST/Fwd.hpp"
    20 class Declaration;
    21 class Expression;
    22 class FunctionDecl;
    23 class Initializer;
    24 class ObjectDecl;
    25 class StructDecl;
    26 class StructInstType;
    27 class Type;
    2820
    2921namespace Virtual {
     
    3729bool isVTableInstanceName( std::string const & name );
    3830
    39 ObjectDecl * makeVtableForward(
    40         std::string const & name, StructInstType * vtableType );
    4131/* Create a forward declaration of a vtable of the given type.
    4232 * vtableType node is consumed.
     
    4636        ast::StructInstType const * vtableType );
    4737
    48 ObjectDecl * makeVtableInstance(
    49         std::string const & name,
    50         StructInstType * vtableType, Type * objectType,
    51         Initializer * init = nullptr );
    5238/* Create an initialized definition of a vtable.
    5339 * vtableType and init (if provided) nodes are consumed.
     
    6147
    6248// Some special code for how exceptions interact with virtual tables.
    63 FunctionDecl * makeGetExceptionForward( Type * vtableType, Type * exceptType );
     49
    6450/* Create a forward declaration of the exception virtual function
    6551 * linking the vtableType to the exceptType. Both nodes are consumed.
     
    7056        ast::Type const * exceptType );
    7157
    72 FunctionDecl * makeGetExceptionFunction(
    73         ObjectDecl * vtableInstance, Type * exceptType );
    7458/* Create the definition of the exception virtual function.
    7559 * exceptType node is consumed.
     
    7963        ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType );
    8064
    81 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
    8265/* Build an instance of the type-id from the type of the type-id.
    8366 * TODO: Should take the parent type. Currently locked to the exception_t.
  • src/main.cc

    r0030b508 rfc12f05  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Sep 28 22:28:45 2023
    13 // Update Count     : 687
     12// Last Modified On : Wed Nov  1 21:12:58 2023
     13// Update Count     : 690
    1414//
    1515
     
    2929#include <string>                           // for char_traits, operator<<
    3030
    31 #include "AST/Convert.hpp"
    3231#include "AST/Pass.hpp"                     // for pass_visitor_stats
     32#include "AST/Print.hpp"                    // for printAll
    3333#include "AST/TranslationUnit.hpp"          // for TranslationUnit
    3434#include "AST/Util.hpp"                     // for checkInvariants
     
    3939#include "CodeGen/Generate.h"               // for generate
    4040#include "CodeGen/LinkOnce.h"               // for translateLinkOnce
    41 #include "CodeTools/TrackLoc.h"             // for fillLocations
    4241#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    4342#include "Common/DeclStats.hpp"             // for printDeclStats
     
    6564#include "ResolvExpr/EraseWith.hpp"         // for eraseWith
    6665#include "ResolvExpr/Resolver.h"            // for resolve
    67 #include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
    68 #include "SynTree/Declaration.h"            // for Declaration
    6966#include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
    7067#include "Validate/Autogen.hpp"             // for autogenerateRoutines
     
    9491        using namespace Stats::Counters;
    9592        {
    96                 static auto group = build<CounterGroup>( "Pass Visitor" );
     93                static auto group = build<CounterGroup>( "Pass Visitor Template" );
    9794                auto pass = build<CounterGroup>( name, group );
    98                 pass_visitor_stats.depth = 0;
    99                 pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass );
    100                 pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass );
    101         }
    102         {
    103                 static auto group = build<CounterGroup>( "Syntax Node" );
    104                 auto pass = build<CounterGroup>( name, group );
    105                 BaseSyntaxNode::new_nodes = build<SimpleCounter>( "Allocs", pass );
     95                ast::pass_visitor_stats.depth = 0;
     96                ast::pass_visitor_stats.avg = build<AverageCounter<double>>( "Average Depth", pass );
     97                ast::pass_visitor_stats.max = build<MaxCounter<double>>( "Max Depth", pass );
    10698        }
    10799}
     
    132124
    133125static void parse_cmdline( int argc, char * argv[] );
    134 static void dump( list< Declaration * > & translationUnit, ostream & out = cout );
    135126static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );
    136127
     
    246237        FILE * input;                                                                           // use FILE rather than istream because yyin is FILE
    247238        ostream * output = & cout;
    248         list< Declaration * > translationUnit;
    249239        ast::TranslationUnit transUnit;
    250240
     
    260250
    261251        parse_cmdline( argc, argv );                                            // process command-line arguments
    262         CodeGen::FixMain::setReplaceMain( !nomainp );
    263252
    264253        if ( waiting_for_gdb ) {
     
    290279
    291280                        // Read to gcc builtins, if not generating the cfa library
    292                         FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" );
     281                        FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cfa").c_str(), "r" );
    293282                        assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
    294283                        parse( gcc_builtins, ast::Linkage::Compiler );
    295284
    296285                        // read the extra prelude in, if not generating the cfa library
    297                         FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" );
     286                        FILE * extras = fopen( (PreludeDirector + "/extras.cfa").c_str(), "r" );
    298287                        assertf( extras, "cannot open extras.cf\n" );
    299288                        parse( extras, ast::Linkage::BuiltinC );
     
    306295
    307296                                // Read to cfa builtins, if not generating the cfa library
    308                                 FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" );
     297                                FILE * builtins = fopen( (PreludeDirector + "/builtins.cfa").c_str(), "r" );
    309298                                assertf( builtins, "cannot open builtins.cf\n" );
    310299                                parse( builtins, ast::Linkage::BuiltinCFA );
     
    319308
    320309                Stats::Time::StopBlock();
    321 
    322                 if (Stats::Counters::enabled) {
    323                         ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
    324                         ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New");
    325                 }
    326310
    327311                PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit );
     
    409393                PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
    410394                PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
     395                PASS( "Fix Main Linkage", CodeGen::fixMainLinkage, transUnit, !nomainp );
    411396
    412397                // Needs to happen before tuple types are expanded.
     
    427412                PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit );
    428413
    429                 translationUnit = convert( std::move( transUnit ) );
    430 
    431414                // Code has been lowered to C, now we can start generation.
    432415
    433                 DUMP( bcodegenp, translationUnit );
     416                DUMP( bcodegenp, std::move( transUnit ) );
    434417
    435418                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    437420                } // if
    438421
    439                 CodeTools::fillLocations( translationUnit );
    440                 PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
    441 
    442                 CodeGen::FixMain::fix( translationUnit, *output,
    443                                 (PreludeDirector + "/bootloader.c").c_str() );
     422                PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false );
     423                CodeGen::fixMainInvoke( transUnit, *output, (PreludeDirector + "/bootloader.c").c_str() );
     424
    444425                if ( output != &cout ) {
    445426                        delete output;
     
    448429                if ( errorp ) {
    449430                        cerr << "---AST at error:---" << endl;
    450                         // We check which section the errors came from without looking at
    451                         // transUnit because std::move means it could look like anything.
    452                         if ( !translationUnit.empty() ) {
    453                                 dump( translationUnit, cerr );
    454                         } else {
    455                                 dump( std::move( transUnit ), cerr );
    456                         }
     431                        dump( std::move( transUnit ), cerr );
    457432                        cerr << endl << "---End of AST, begin error message:---\n" << endl;
    458433                } // if
     
    480455        } // try
    481456
    482         deleteAll( translationUnit );
    483457        Stats::print();
    484458        return EXIT_SUCCESS;
     
    710684} // parse_cmdline
    711685
    712 static bool notPrelude( Declaration * decl ) {
    713         return ! LinkageSpec::isBuiltin( decl->get_linkage() );
    714 } // notPrelude
    715 
    716 static void dump( list< Declaration * > & translationUnit, ostream & out ) {
    717         list< Declaration * > decls;
    718 
     686static bool notPrelude( ast::ptr<ast::Decl> & decl ) {
     687        return !decl->linkage.is_builtin;
     688}
     689
     690static void dump( ast::TranslationUnit && unit, std::ostream & out ) {
     691        // May filter out all prelude declarations.
    719692        if ( genproto ) {
    720                 filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), notPrelude );
     693                std::list<ast::ptr<ast::Decl>> decls;
     694                std::copy_if( unit.decls.begin(), unit.decls.end(),
     695                        std::back_inserter( decls ), notPrelude );
     696                decls.swap( unit.decls );
     697        }
     698
     699        // May print as full dump or as code generation.
     700        if ( codegenp ) {
     701                CodeGen::generate( unit, out, !genproto, prettycodegenp, false, false, false );
    721702        } else {
    722                 decls = translationUnit;
    723         } // if
    724 
    725         // depending on commandline options, either generate code or dump the AST
    726         if ( codegenp ) {
    727                 CodeGen::generate( decls, out, ! genproto, prettycodegenp );
    728         } else {
    729                 printAll( decls, out );
    730         } // if
    731         deleteAll( translationUnit );
    732 } // dump
    733 
    734 static void dump( ast::TranslationUnit && transUnit, ostream & out ) {
    735         std::list< Declaration * > translationUnit = convert( std::move( transUnit ) );
    736         dump( translationUnit, out );
     703                ast::printAll( out, unit.decls );
     704        }
    737705}
    738706
Note: See TracChangeset for help on using the changeset viewer.