Changeset 58fe85a for src


Ignore:
Timestamp:
Jan 7, 2021, 3:27:00 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
2b4daf2, 64aeca0
Parents:
3c64c668 (diff), eef8dfb (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' into park_unpark

Location:
src
Files:
12 added
1 deleted
146 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Attribute.hpp

    r3c64c668 r58fe85a  
    5151        template<typename node_t>
    5252        friend node_t * mutate(const node_t * node);
     53        template<typename node_t>
     54    friend node_t * shallowCopy(const node_t * node);
    5355};
    5456
  • src/AST/CVQualifiers.hpp

    r3c64c668 r58fe85a  
    2727                Restrict = 1 << 1,
    2828                Volatile = 1 << 2,
    29                 Lvalue   = 1 << 3,
    30                 Mutex    = 1 << 4,
    31                 Atomic   = 1 << 5,
    32                 NumQualifiers = 6
     29                Mutex    = 1 << 3,
     30                Atomic   = 1 << 4,
     31                NumQualifiers = 5
    3332        };
    3433
    3534        /// Mask for equivalence-preserving qualfiers
    36         enum { EquivQualifiers = ~(Restrict | Lvalue) };
     35        enum { EquivQualifiers = ~Restrict };
    3736
    3837        /// Underlying data for qualifiers
     
    4443                                bool is_restrict : 1;
    4544                                bool is_volatile : 1;
    46                                 bool is_lvalue   : 1;
    4745                                bool is_mutex    : 1;
    4846                                bool is_atomic   : 1;
  • src/AST/Convert.cpp

    r3c64c668 r58fe85a  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 09 15::37::05 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:39:32 2019
    13 // Update Count     : 33
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Nov 12 10:07:00 2020
     13// Update Count     : 34
    1414//
    1515
     
    2020
    2121#include "AST/Attribute.hpp"
     22#include "AST/Copy.hpp"
    2223#include "AST/Decl.hpp"
    2324#include "AST/Expr.hpp"
    2425#include "AST/Init.hpp"
    2526#include "AST/Stmt.hpp"
     27#include "AST/TranslationUnit.hpp"
    2628#include "AST/TypeSubstitution.hpp"
    2729
     
    4648
    4749//================================================================================================
    48 namespace {
     50namespace ast {
    4951
    5052// This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not)
    5153// allow us to use the same stratagy in the new ast.
    52 ast::Type * sizeType = nullptr;
    53 ast::FunctionDecl * dereferenceOperator = nullptr;
    54 ast::StructDecl   * dtorStruct = nullptr;
    55 ast::FunctionDecl * dtorStructDestroy = nullptr;
     54// xxx - since convert back pass works, this concern seems to be unnecessary.
     55
     56// these need to be accessed in new FixInit now
     57ast::ptr<ast::Type> sizeType = nullptr;
     58const ast::FunctionDecl * dereferenceOperator = nullptr;
     59const ast::StructDecl   * dtorStruct = nullptr;
     60const ast::FunctionDecl * dtorStructDestroy = nullptr;
    5661
    5762}
     
    6267        using Cache = std::unordered_map< const ast::Node *, BaseSyntaxNode * >;
    6368        Cache cache;
     69
     70        // Statements can no longer be shared.
     71        // however, since StmtExprResult is now implemented, need to still maintain
     72        // readonly references.
     73        Cache readonlyCache;
    6474
    6575        template<typename T>
     
    153163        }
    154164
    155         const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {
    156                 auto&& bfwd = get<Expression>().accept1( node->bitfieldWidth );
    157                 auto&& type = get<Type>().accept1( node->type );
    158                 auto&& init = get<Initializer>().accept1( node->init );
    159                 auto&& attr = get<Attribute>().acceptL( node->attributes );
     165        const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final {       
    160166                if ( inCache( node ) ) {
    161167                        return nullptr;
    162168                }
     169                auto bfwd = get<Expression>().accept1( node->bitfieldWidth );
     170                auto type = get<Type>().accept1( node->type );
     171                auto attr = get<Attribute>().acceptL( node->attributes );
     172
    163173                auto decl = new ObjectDecl(
    164174                        node->name,
     
    166176                        LinkageSpec::Spec( node->linkage.val ),
    167177                        bfwd,
    168                         type,
    169                         init,
     178                        type->clone(),
     179                        nullptr, // prevent infinite loop
    170180                        attr,
    171181                        Type::FuncSpecifiers( node->funcSpec.val )
    172182                );
    173                 return declWithTypePostamble( decl, node );
     183
     184                // handles the case where node->init references itself
     185                // xxx - does it really happen?
     186                declWithTypePostamble(decl, node);
     187                auto init = get<Initializer>().accept1( node->init );
     188                decl->init = init;
     189
     190                this->node = decl;
     191                return nullptr;
    174192        }
    175193
    176194        const ast::DeclWithType * visit( const ast::FunctionDecl * node ) override final {
    177195                if ( inCache( node ) ) return nullptr;
     196
     197                // function decl contains real variables that the type must use.
     198                // the structural change means function type in and out of decl
     199                // must be handled **differently** on convert back to old.
     200                auto ftype = new FunctionType(
     201                        cv(node->type),
     202                        (bool)node->type->isVarArgs
     203                );
     204                ftype->returnVals = get<DeclarationWithType>().acceptL(node->returns);
     205                ftype->parameters = get<DeclarationWithType>().acceptL(node->params);
     206
     207                ftype->forall = get<TypeDecl>().acceptL( node->type_params );
     208                if (!node->assertions.empty()) {
     209                        assert(!ftype->forall.empty());
     210                        // find somewhere to place assertions back, for convenience it is the last slot
     211                        ftype->forall.back()->assertions = get<DeclarationWithType>().acceptL(node->assertions);
     212                }
     213
     214                visitType(node->type, ftype);
     215
    178216                auto decl = new FunctionDecl(
    179217                        node->name,
    180218                        Type::StorageClasses( node->storage.val ),
    181219                        LinkageSpec::Spec( node->linkage.val ),
    182                         get<FunctionType>().accept1( node->type ),
     220                        ftype,
     221                        //get<FunctionType>().accept1( node->type ),
    183222                        {},
    184223                        get<Attribute>().acceptL( node->attributes ),
     
    188227                decl->statements = get<CompoundStmt>().accept1( node->stmts );
    189228                decl->withExprs = get<Expression>().acceptL( node->withExprs );
    190                 if ( dereferenceOperator == node ) {
     229                if ( ast::dereferenceOperator == node ) {
    191230                        Validate::dereferenceOperator = decl;
    192231                }
    193                 if ( dtorStructDestroy == node ) {
     232                if ( ast::dtorStructDestroy == node ) {
    194233                        Validate::dtorStructDestroy = decl;
    195234                }
     
    199238        const ast::Decl * namedTypePostamble( NamedTypeDecl * decl, const ast::NamedTypeDecl * node ) {
    200239                // base comes from constructor
    201                 decl->parameters = get<TypeDecl>().acceptL( node->params );
    202240                decl->assertions = get<DeclarationWithType>().acceptL( node->assertions );
    203241                declPostamble( decl, node );
     
    250288                );
    251289
    252                 if ( dtorStruct == node ) {
     290                if ( ast::dtorStruct == node ) {
    253291                        Validate::dtorStruct = decl;
    254292                }
     
    303341
    304342        const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) {
    305                 cache.emplace( node, stmt );
     343                // force statements in old tree to be unique.
     344                // cache.emplace( node, stmt );
     345                readonlyCache.emplace( node, stmt );
    306346                stmt->location = node->location;
    307347                stmt->labels = makeLabelL( stmt, node->labels );
     
    320360                if ( inCache( node ) ) return nullptr;
    321361                auto stmt = new ExprStmt( nullptr );
    322                 cache.emplace( node, stmt );
    323362                stmt->expr = get<Expression>().accept1( node->expr );
    324363                return stmtPostamble( stmt, node );
     
    493532        }
    494533
     534        const ast::Stmt * visit(const ast::SuspendStmt * node ) override final {
     535                if ( inCache( node ) ) return nullptr;
     536                auto stmt = new SuspendStmt();
     537                stmt->then   = get<CompoundStmt>().accept1( node->then   );
     538                switch(node->type) {
     539                        case ast::SuspendStmt::None     : stmt->type = SuspendStmt::None     ; break;
     540                        case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;
     541                        case ast::SuspendStmt::Generator: stmt->type = SuspendStmt::Generator; break;
     542                }
     543                return stmtPostamble( stmt, node );
     544        }
     545
    495546        const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    496547                if ( inCache( node ) ) return nullptr;
     
    556607
    557608                for (decltype(src->begin()) src_i = src->begin(); src_i != src->end(); src_i++) {
    558                         rslt->add( src_i->first,
     609                        rslt->add( src_i->first.typeString(),
    559610                                   get<Type>().accept1(src_i->second) );
    560                 }
    561 
    562                 for (decltype(src->beginVar()) src_i = src->beginVar(); src_i != src->endVar(); src_i++) {
    563                         rslt->addVar( src_i->first,
    564                                       get<Expression>().accept1(src_i->second) );
    565611                }
    566612
     
    575621                assert( tgtResnSlots.empty() );
    576622
    577                 if ( srcInferred.mode == ast::Expr::InferUnion::Params ) {
     623                if ( srcInferred.data.inferParams ) {
    578624                        const ast::InferredParams &srcParams = srcInferred.inferParams();
    579625                        for (auto & srcParam : srcParams) {
     
    581627                                        srcParam.second.decl,
    582628                                        get<Declaration>().accept1(srcParam.second.declptr),
    583                                         get<Type>().accept1(srcParam.second.actualType),
    584                                         get<Type>().accept1(srcParam.second.formalType),
    585                                         get<Expression>().accept1(srcParam.second.expr)
     629                                        get<Type>().accept1(srcParam.second.actualType)->clone(),
     630                                        get<Type>().accept1(srcParam.second.formalType)->clone(),
     631                                        get<Expression>().accept1(srcParam.second.expr)->clone()
    586632                                ));
    587633                                assert(res.second);
    588634                        }
    589                 } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots  ) {
     635                }
     636                if ( srcInferred.data.resnSlots ) {
    590637                        const ast::ResnSlots &srcSlots = srcInferred.resnSlots();
    591638                        for (auto srcSlot : srcSlots) {
     
    608655
    609656                tgt->result = get<Type>().accept1(src->result);
     657                // Unconditionally use a clone of the result type.
     658                // We know this will leak some objects: much of the immediate conversion result.
     659                // In some cases, using the conversion result directly gives unintended object sharing.
     660                // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache.
     661                // But tgt->result must be fully owned privately by tgt.
     662                // Applying these conservative copies here means
     663                // - weak references point at the declaration's copy, not these expr.result copies (good)
     664                // - we copy more objects than really needed (bad, tolerated)
     665                if (tgt->result) {
     666                        tgt->result = tgt->result->clone();
     667                }
    610668                return visitBaseExpr_skipResultType(src, tgt);
    611669        }
     
    680738                        new KeywordCastExpr(
    681739                                get<Expression>().accept1(node->arg),
    682                                 castTarget
     740                                castTarget,
     741                                {node->concrete_target.field, node->concrete_target.getter}
    683742                        )
    684743                );
     
    9671026
    9681027        const ast::Expr * visit( const ast::StmtExpr * node ) override final {
     1028                auto stmts = node->stmts;
     1029                // disable sharing between multiple StmtExprs explicitly.
     1030                // this should no longer be true.
     1031
    9691032                auto rslt = new StmtExpr(
    970                         get<CompoundStmt>().accept1(node->stmts)
     1033                        get<CompoundStmt>().accept1(stmts)
    9711034                );
    9721035
    9731036                rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls);
    9741037                rslt->dtors       = get<Expression>().acceptL(node->dtors);
     1038                if (node->resultExpr) {
     1039                        // this MUST be found by children visit
     1040                        rslt->resultExpr  = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr));
     1041                }
    9751042
    9761043                auto expr = visitBaseExpr( node, rslt );
     
    9891056
    9901057                auto expr = visitBaseExpr( node, rslt );
    991                 this->node = expr;
     1058                this->node = expr->clone();
    9921059                return nullptr;
    9931060        }
     
    10791146                auto type = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind };
    10801147                // I believe this should always be a BasicType.
    1081                 if ( sizeType == node ) {
     1148                if ( ast::sizeType == node ) {
    10821149                        Validate::SizeType = type;
    10831150                }
     
    11211188
    11221189        const ast::Type * visit( const ast::FunctionType * node ) override final {
     1190                static std::string dummy_paramvar_prefix = "__param_";
     1191                static std::string dummy_returnvar_prefix = "__retval_";
     1192
    11231193                auto ty = new FunctionType {
    11241194                        cv( node ),
    11251195                        (bool)node->isVarArgs
    11261196                };
    1127                 ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
    1128                 ty->parameters = get<DeclarationWithType>().acceptL( node->params );
    1129                 ty->forall = get<TypeDecl>().acceptL( node->forall );
     1197                auto returns = get<Type>().acceptL(node->returns);
     1198                auto params = get<Type>().acceptL(node->params);
     1199
     1200                int ret_index = 0;
     1201                for (auto t: returns) {
     1202                        // xxx - LinkageSpec shouldn't matter but needs to be something
     1203                        ObjectDecl * dummy = new ObjectDecl(dummy_returnvar_prefix + std::to_string(ret_index++), {}, LinkageSpec::C, nullptr, t, nullptr);
     1204                        ty->returnVals.push_back(dummy);
     1205                }
     1206                int param_index = 0;
     1207                for (auto t: params) {
     1208                        ObjectDecl * dummy = new ObjectDecl(dummy_paramvar_prefix + std::to_string(param_index++), {}, LinkageSpec::C, nullptr, t, nullptr);
     1209                        ty->parameters.push_back(dummy);
     1210                }
     1211
     1212                // ty->returnVals = get<DeclarationWithType>().acceptL( node->returns );
     1213                // ty->parameters = get<DeclarationWithType>().acceptL( node->params );
     1214
     1215                auto types = get<TypeInstType>().acceptL( node->forall );
     1216                for (auto t : types) {
     1217                        auto newT = new TypeDecl(*t->baseType);
     1218                        newT->name = t->name; // converted by typeString()
     1219                        for (auto asst : newT->assertions) delete asst;
     1220                        newT->assertions.clear();
     1221                        ty->forall.push_back(newT);
     1222                }
     1223                auto assts = get<VariableExpr>().acceptL( node->assertions );
     1224                if (!assts.empty()) {
     1225                        assert(!types.empty());
     1226                        for (auto asst : assts) {
     1227                                auto newDecl = new ObjectDecl(*strict_dynamic_cast<ObjectDecl*>(asst->var));
     1228                                delete newDecl->type;
     1229                                newDecl->type = asst->result->clone();
     1230                                newDecl->storageClasses.is_extern = true; // hack
     1231                                ty->forall.back()->assertions.push_back(newDecl);
     1232                        }
     1233                }
     1234
    11301235                return visitType( node, ty );
    11311236        }
    11321237
    1133         const ast::Type * postvisit( const ast::ReferenceToType * old, ReferenceToType * ty ) {
    1134                 ty->forall = get<TypeDecl>().acceptL( old->forall );
     1238        const ast::Type * postvisit( const ast::BaseInstType * old, ReferenceToType * ty ) {
    11351239                ty->parameters = get<Expression>().acceptL( old->params );
    11361240                ty->hoistType = old->hoistType;
     
    12151319                        ty = new TypeInstType{
    12161320                                cv( node ),
    1217                                 node->name,
     1321                                node->typeString(),
    12181322                                get<TypeDecl>().accept1( node->base ),
    12191323                                get<Attribute>().acceptL( node->attributes )
     
    12221326                        ty = new TypeInstType{
    12231327                                cv( node ),
    1224                                 node->name,
     1328                                node->typeString(),
    12251329                                node->kind == ast::TypeDecl::Ftype,
    12261330                                get<Attribute>().acceptL( node->attributes )
     
    13191423};
    13201424
    1321 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit ) {
     1425std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ) {
    13221426        ConverterNewToOld c;
    13231427        std::list< Declaration * > decls;
    1324         for(auto d : translationUnit) {
     1428        for(auto d : translationUnit.decls) {
    13251429                decls.emplace_back( c.decl( d ) );
    13261430        }
     
    13431447        ast::Node * node = nullptr;
    13441448        /// cache of nodes that might be referenced by readonly<> for de-duplication
    1345         std::unordered_map< const BaseSyntaxNode *, ast::Node * > cache = {};
     1449        /// in case that some nodes are dropped by conversion (due to possible structural change)
     1450        /// use smart pointers in cache value to prevent accidental invalidation.
     1451        /// at conversion stage, all created nodes are guaranteed to be unique, therefore
     1452        /// const_casting out of smart pointers is permitted.
     1453        std::unordered_map< const BaseSyntaxNode *, ast::readonly<ast::Node> > cache = {};
    13461454
    13471455        // Local Utilities:
     
    14161524                auto it = cache.find( old );
    14171525                if ( it == cache.end() ) return false;
    1418                 node = it->second;
     1526                node = const_cast<ast::Node *>(it->second.get());
    14191527                return true;
    14201528        }
     
    14551563        virtual void visit( const FunctionDecl * old ) override final {
    14561564                if ( inCache( old ) ) return;
     1565                auto paramVars = GET_ACCEPT_V(type->parameters, DeclWithType);
     1566                auto returnVars = GET_ACCEPT_V(type->returnVals, DeclWithType);
     1567                auto forall = GET_ACCEPT_V(type->forall, TypeDecl);
     1568
     1569                // function type is now derived from parameter decls instead of storing them
     1570
     1571                /*
     1572                auto ftype = new ast::FunctionType((ast::ArgumentFlag)old->type->isVarArgs, cv(old->type));
     1573                ftype->params.reserve(paramVars.size());
     1574                ftype->returns.reserve(returnVars.size());
     1575
     1576                for (auto & v: paramVars) {
     1577                        ftype->params.emplace_back(v->get_type());
     1578                }
     1579                for (auto & v: returnVars) {
     1580                        ftype->returns.emplace_back(v->get_type());
     1581                }
     1582                ftype->forall = std::move(forall);
     1583                */
     1584
     1585                // can function type have attributes? seems not to be the case.
     1586                // visitType(old->type, ftype);
     1587
     1588                // collect assertions and put directly in FunctionDecl
     1589                std::vector<ast::ptr<ast::DeclWithType>> assertions;
     1590                for (auto & param: forall) {
     1591                        for (auto & asst: param->assertions) {
     1592                                assertf(asst->unique(), "newly converted decl must be unique");
     1593                                assertions.emplace_back(asst);
     1594                        }
     1595                        auto mut = param.get_and_mutate();
     1596                        assertf(mut == param, "newly converted decl must be unique");
     1597                        mut->assertions.clear();
     1598                }
     1599
    14571600                auto decl = new ast::FunctionDecl{
    14581601                        old->location,
    14591602                        old->name,
    1460                         GET_ACCEPT_1(type, FunctionType),
     1603                        // GET_ACCEPT_1(type, FunctionType),
     1604                        std::move(forall),
     1605                        std::move(paramVars),
     1606                        std::move(returnVars),
    14611607                        {},
    14621608                        { old->storageClasses.val },
    14631609                        { old->linkage.val },
    14641610                        GET_ACCEPT_V(attributes, Attribute),
    1465                         { old->get_funcSpec().val }
     1611                        { old->get_funcSpec().val },
     1612                        old->type->isVarArgs
    14661613                };
     1614
     1615                // decl->type = ftype;
    14671616                cache.emplace( old, decl );
     1617
     1618                decl->assertions = std::move(assertions);
    14681619                decl->withExprs = GET_ACCEPT_V(withExprs, Expr);
    14691620                decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
     
    14781629
    14791630                if ( Validate::dereferenceOperator == old ) {
    1480                         dereferenceOperator = decl;
     1631                        ast::dereferenceOperator = decl;
    14811632                }
    14821633
    14831634                if ( Validate::dtorStructDestroy == old ) {
    1484                         dtorStructDestroy = decl;
     1635                        ast::dtorStructDestroy = decl;
    14851636                }
    14861637        }
     
    15071658
    15081659                if ( Validate::dtorStruct == old ) {
    1509                         dtorStruct = decl;
     1660                        ast::dtorStruct = decl;
    15101661                }
    15111662        }
     
    15841735                cache.emplace( old, decl );
    15851736                decl->assertions = GET_ACCEPT_V(assertions, DeclWithType);
    1586                 decl->params     = GET_ACCEPT_V(parameters, TypeDecl);
    15871737                decl->extension  = old->extension;
    15881738                decl->uniqueId   = old->uniqueId;
     
    16001750                );
    16011751                decl->assertions = GET_ACCEPT_V(assertions, DeclWithType);
    1602                 decl->params     = GET_ACCEPT_V(parameters, TypeDecl);
    16031752                decl->extension  = old->extension;
    16041753                decl->uniqueId   = old->uniqueId;
     
    18592008        }
    18602009
     2010        virtual void visit( const SuspendStmt * old ) override final {
     2011                if ( inCache( old ) ) return;
     2012                ast::SuspendStmt::Type type;
     2013                switch (old->type) {
     2014                        case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;
     2015                        case SuspendStmt::Generator: type = ast::SuspendStmt::Generator; break;
     2016                        case SuspendStmt::None     : type = ast::SuspendStmt::None     ; break;
     2017                        default: abort();
     2018                }
     2019                this->node = new ast::SuspendStmt(
     2020                        old->location,
     2021                        GET_ACCEPT_1(then  , CompoundStmt),
     2022                        type,
     2023                        GET_LABELS_V(old->labels)
     2024                );
     2025                cache.emplace( old, this->node );
     2026        }
     2027
    18612028        virtual void visit( const WaitForStmt * old ) override final {
    18622029                if ( inCache( old ) ) return;
     
    19322099        }
    19332100
     2101        // TypeSubstitution shouldn't exist yet in old.
    19342102        ast::TypeSubstitution * convertTypeSubstitution(const TypeSubstitution * old) {
    1935 
     2103               
    19362104                if (!old) return nullptr;
    1937 
     2105                if (old->empty()) return nullptr;
     2106                assert(false);
     2107
     2108                /*
    19382109                ast::TypeSubstitution *rslt = new ast::TypeSubstitution();
    19392110
     
    19432114                }
    19442115
    1945                 for (decltype(old->beginVar()) old_i = old->beginVar(); old_i != old->endVar(); old_i++) {
    1946                         rslt->addVar( old_i->first,
    1947                                       getAccept1<ast::Expr>(old_i->second) );
    1948                 }
    1949 
    19502116                return rslt;
     2117                */
    19512118        }
    19522119
     
    19562123
    19572124                assert( oldInferParams.empty() || oldResnSlots.empty() );
    1958                 assert( newInferred.mode == ast::Expr::InferUnion::Empty );
     2125                // assert( newInferred.mode == ast::Expr::InferUnion::Empty );
    19592126
    19602127                if ( !oldInferParams.empty() ) {
     
    20392206                                old->location,
    20402207                                GET_ACCEPT_1(arg, Expr),
    2041                                 castTarget
     2208                                castTarget,
     2209                                {old->concrete_target.field, old->concrete_target.getter}
    20422210                        )
    20432211                );
     
    20872255                                old->location,
    20882256                                GET_ACCEPT_1(member, DeclWithType),
    2089                                 GET_ACCEPT_1(aggregate, Expr)
     2257                                GET_ACCEPT_1(aggregate, Expr),
     2258                                ast::MemberExpr::NoOpConstructionChosen
    20902259                        )
    20912260                );
     
    24192588                // I believe this should always be a BasicType.
    24202589                if ( Validate::SizeType == old ) {
    2421                         sizeType = type;
     2590                        ast::sizeType = type;
    24222591                }
    24232592                visitType( old, type );
     
    24642633                        cv( old )
    24652634                };
    2466                 ty->returns = GET_ACCEPT_V( returnVals, DeclWithType );
    2467                 ty->params = GET_ACCEPT_V( parameters, DeclWithType );
    2468                 ty->forall = GET_ACCEPT_V( forall, TypeDecl );
     2635                auto returnVars = GET_ACCEPT_V(returnVals, DeclWithType);
     2636                auto paramVars = GET_ACCEPT_V(parameters, DeclWithType);
     2637                // ty->returns = GET_ACCEPT_V( returnVals, DeclWithType );
     2638                // ty->params = GET_ACCEPT_V( parameters, DeclWithType );
     2639                for (auto & v: returnVars) {
     2640                        ty->returns.emplace_back(v->get_type());
     2641                }
     2642                for (auto & v: paramVars) {
     2643                        ty->params.emplace_back(v->get_type());
     2644                }
     2645                // xxx - when will this be non-null?
     2646                // will have to create dangling (no-owner) decls to be pointed to
     2647                auto foralls = GET_ACCEPT_V( forall, TypeDecl );
     2648
     2649                for (auto & param : foralls) {
     2650                        ty->forall.emplace_back(new ast::TypeInstType(param->name, param));
     2651                        for (auto asst : param->assertions) {
     2652                                ty->assertions.emplace_back(new ast::VariableExpr({}, asst));
     2653                        }
     2654                }
    24692655                visitType( old, ty );
    24702656        }
    24712657
    2472         void postvisit( const ReferenceToType * old, ast::ReferenceToType * ty ) {
    2473                 ty->forall = GET_ACCEPT_V( forall, TypeDecl );
     2658        void postvisit( const ReferenceToType * old, ast::BaseInstType * ty ) {
    24742659                ty->params = GET_ACCEPT_V( parameters, Expr );
    24752660                ty->hoistType = old->hoistType;
     
    26162801                        old->location,
    26172802                        GET_ACCEPT_1(value, Expr),
    2618                         (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::DoConstruct
     2803                        (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::NoConstruct
    26192804                );
    26202805        }
     
    26252810                        GET_ACCEPT_V(initializers, Init),
    26262811                        GET_ACCEPT_V(designations, Designation),
    2627                         (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::DoConstruct
     2812                        (old->get_maybeConstructed()) ? ast::MaybeConstruct : ast::NoConstruct
    26282813                );
    26292814        }
     
    26562841#undef GET_ACCEPT_1
    26572842
    2658 std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit ) {
     2843ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit ) {
    26592844        ConverterOldToNew c;
    2660         std::list< ast::ptr< ast::Decl > > decls;
     2845        ast::TranslationUnit unit;
     2846        if (Validate::SizeType) {
     2847                // this should be a BasicType.
     2848                auto old = strict_dynamic_cast<BasicType *>(Validate::SizeType);
     2849                ast::sizeType = new ast::BasicType{ (ast::BasicType::Kind)(unsigned)old->kind };
     2850        }
     2851
    26612852        for(auto d : translationUnit) {
    26622853                d->accept( c );
    2663                 decls.emplace_back( c.decl() );
     2854                unit.decls.emplace_back( c.decl() );
    26642855        }
    26652856        deleteAll(translationUnit);
    2666         return decls;
     2857
     2858        // Load the local static varables into the global store.
     2859        unit.global.sizeType = ast::sizeType;
     2860        unit.global.dereference = ast::dereferenceOperator;
     2861        unit.global.dtorStruct = ast::dtorStruct;
     2862        unit.global.dtorDestroy = ast::dtorStructDestroy;
     2863
     2864        return unit;
    26672865}
  • src/AST/Convert.hpp

    r3c64c668 r58fe85a  
    1818#include <list>
    1919
    20 #include "AST/Node.hpp"
    21 
    2220class Declaration;
    2321namespace ast {
    24         class Decl;
     22        struct TranslationUnit;
    2523};
    2624
    27 std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > && translationUnit );
    28 std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > && translationUnit );
     25std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit );
     26ast::TranslationUnit convert( const std::list< Declaration * > && translationUnit );
  • src/AST/Decl.cpp

    r3c64c668 r58fe85a  
    4949// --- FunctionDecl
    5050
     51FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name,
     52        std::vector<ptr<TypeDecl>>&& forall,
     53        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
     54        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
     55        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     56: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
     57        type_params(std::move(forall)), stmts( stmts ) {
     58        FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
     59        for (auto & param : this->params) {
     60                ftype->params.emplace_back(param->get_type());
     61        }
     62        for (auto & ret : this->returns) {
     63                ftype->returns.emplace_back(ret->get_type());
     64        }
     65        for (auto & tp : this->type_params) {
     66                ftype->forall.emplace_back(new TypeInstType(tp->name, tp));
     67        }
     68        this->type = ftype;
     69}
     70
     71
    5172const Type * FunctionDecl::get_type() const { return type.get(); }
    52 void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); }
     73void FunctionDecl::set_type( const Type * t ) {
     74        type = strict_dynamic_cast< const FunctionType * >( t );
     75}
    5376
    5477// --- TypeDecl
  • src/AST/Decl.hpp

    r3c64c668 r58fe85a  
    3333
    3434// Must be included in *all* AST classes; should be #undef'd at the end of the file
    35 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     35#define MUTATE_FRIEND \
     36    template<typename node_t> friend node_t * mutate(const node_t * node); \
     37        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3638
    3739namespace ast {
     
    7779        ptr<Expr> asmName;
    7880        bool isDeleted = false;
     81        bool isTypeFixed = false;
    7982
    8083        DeclWithType( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
     
    8891        virtual const Type * get_type() const = 0;
    8992        /// Set type of this declaration. May be verified by subclass
    90         virtual void set_type(Type *) = 0;
     93        virtual void set_type( const Type * ) = 0;
    9194
    9295        const DeclWithType * accept( Visitor & v ) const override = 0;
     
    111114
    112115        const Type* get_type() const override { return type; }
    113         void set_type( Type * ty ) override { type = ty; }
     116        void set_type( const Type * ty ) override { type = ty; }
    114117
    115118        const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
     
    122125class FunctionDecl : public DeclWithType {
    123126public:
     127        std::vector<ptr<DeclWithType>> params;
     128        std::vector<ptr<DeclWithType>> returns;
     129        std::vector<ptr<TypeDecl>> type_params;
     130        std::vector<ptr<DeclWithType>> assertions;
     131        // declared type, derived from parameter declarations
    124132        ptr<FunctionType> type;
    125133        ptr<CompoundStmt> stmts;
    126134        std::vector< ptr<Expr> > withExprs;
    127135
    128         FunctionDecl( const CodeLocation & loc, const std::string & name, FunctionType * type,
     136
     137        FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
     138                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    129139                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
    130                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
    131         : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ),
    132           stmts( stmts ) {}
     140                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
     141        // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)),
     142        //  stmts( stmts ) {}
    133143
    134144        const Type * get_type() const override;
    135         void set_type(Type * t) override;
     145        void set_type( const Type * t ) override;
    136146
    137147        bool has_body() const { return stmts; }
     
    147157public:
    148158        ptr<Type> base;
    149         std::vector<ptr<TypeDecl>> params;
    150159        std::vector<ptr<DeclWithType>> assertions;
    151160
    152         NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
    153                 Type* b, Linkage::Spec spec = Linkage::Cforall )
    154         : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
     161        NamedTypeDecl(
     162                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
     163                const Type * b, Linkage::Spec spec = Linkage::Cforall )
     164        : Decl( loc, name, storage, spec ), base( b ), assertions() {}
    155165
    156166        /// Produces a name for the kind of alias
     
    186196        };
    187197
    188         TypeDecl( const CodeLocation & loc, const std::string & name, Storage::Classes storage, Type * b,
    189                           Kind k, bool s, Type * i = nullptr )
    190                 : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ),
    191                 init( i ) {}
     198        TypeDecl(
     199                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
     200                const Type * b, TypeDecl::Kind k, bool s, const Type * i = nullptr )
     201        : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeDecl::Ttype || s ),
     202          init( i ) {}
    192203
    193204        const char * typeString() const override;
     
    259270
    260271        bool is_coroutine() { return kind == Coroutine; }
    261         bool is_monitor() { return kind == Monitor; }
    262         bool is_thread() { return kind == Thread; }
     272        bool is_generator() { return kind == Generator; }
     273        bool is_monitor  () { return kind == Monitor  ; }
     274        bool is_thread   () { return kind == Thread   ; }
    263275
    264276        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/DeclReplacer.cpp

    r3c64c668 r58fe85a  
    3838                        const ast::TypeInstType * previsit( const ast::TypeInstType * );
    3939                };
     40
     41                struct VarExprReplacer {
     42                private:
     43                        const ExprMap & exprMap;
     44                       
     45                public:
     46                        VarExprReplacer(const ExprMap & exprMap): exprMap (exprMap) {}
     47
     48                        const Expr * postvisit (const VariableExpr *);
     49                };
    4050        }
    4151
     
    5464                DeclMap declMap;
    5565                return replace( node, declMap, typeMap, debug );
     66        }
     67
     68        const ast::Node * replace( const ast::Node * node, const ExprMap & exprMap) {
     69                Pass<VarExprReplacer> replacer = {exprMap};
     70                return node->accept( replacer );
    5671        }
    5772
     
    88103                        return ninst;
    89104                }
     105
     106                const Expr * VarExprReplacer::postvisit( const VariableExpr * expr ) {
     107                        if (!exprMap.count(expr->var)) return expr;
     108
     109                        return exprMap.at(expr->var);
     110                }
     111
    90112        }
    91113}
  • src/AST/DeclReplacer.hpp

    r3c64c668 r58fe85a  
    2323        class DeclWithType;
    2424        class TypeDecl;
     25        class Expr;
    2526
    2627        namespace DeclReplacer {
    2728                using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
    2829                using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
     30                using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;
    2931
    3032                const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
    3133                const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
    3234                const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
     35                const Node * replace( const Node * node, const ExprMap & exprMap);
    3336        }
    3437}
  • src/AST/Expr.cpp

    r3c64c668 r58fe85a  
    2020#include <vector>
    2121
     22#include "Copy.hpp"                // for shallowCopy
     23#include "Eval.hpp"                // for call
    2224#include "GenericSubstitution.hpp"
     25#include "LinkageSpec.hpp"
    2326#include "Stmt.hpp"
    2427#include "Type.hpp"
     
    2730#include "Common/SemanticError.h"
    2831#include "GenPoly/Lvalue.h"        // for referencesPermissable
    29 #include "InitTweak/InitTweak.h"   // for getPointerBase
     32#include "InitTweak/InitTweak.h"   // for getFunction, getPointerBase
    3033#include "ResolvExpr/typeops.h"    // for extractResultType
    3134#include "Tuples/Tuples.h"         // for makeTupleType
    3235
    3336namespace ast {
     37
     38namespace {
     39        std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
     40}
     41
     42// --- Expr
     43bool Expr::get_lvalue() const {
     44        return false;
     45}
    3446
    3547// --- ApplicationExpr
     
    4658}
    4759
     60bool ApplicationExpr::get_lvalue() const {
     61        if ( const DeclWithType * func = InitTweak::getFunction( this ) ) {
     62                return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
     63        }
     64        return false;
     65}
     66
    4867// --- UntypedExpr
    4968
    50 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, Expr * arg ) {
     69UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) {
    5170        assert( arg );
    5271
    53         UntypedExpr * ret = new UntypedExpr{
    54                 loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
    55         };
     72        UntypedExpr * ret = call( loc, "*?", arg );
    5673        if ( const Type * ty = arg->result ) {
    5774                const Type * base = InitTweak::getPointerBase( ty );
     
    6582                        // base type
    6683                        ret->result = base;
    67                         add_qualifiers( ret->result, CV::Lvalue );
    6884                }
    6985        }
     
    7187}
    7288
    73 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ) {
     89bool UntypedExpr::get_lvalue() const {
     90        std::string fname = InitTweak::getFunctionName( this );
     91        return lvalueFunctionNames.count( fname );
     92}
     93
     94UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) {
    7495        assert( lhs && rhs );
    7596
    76         UntypedExpr * ret = new UntypedExpr{
    77                 loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
    78         };
     97        UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
    7998        if ( lhs->result && rhs->result ) {
    8099                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
     
    83102        }
    84103        return ret;
     104}
     105
     106// --- VariableExpr
     107
     108VariableExpr::VariableExpr( const CodeLocation & loc )
     109: Expr( loc ), var( nullptr ) {}
     110
     111VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )
     112: Expr( loc ), var( v ) {
     113        assert( var );
     114        assert( var->get_type() );
     115        result = shallowCopy( var->get_type() );
     116}
     117
     118bool VariableExpr::get_lvalue() const {
     119        // It isn't always an lvalue, but it is never an rvalue.
     120        return true;
     121}
     122
     123VariableExpr * VariableExpr::functionPointer(
     124                const CodeLocation & loc, const FunctionDecl * decl ) {
     125        // wrap usually-determined result type in a pointer
     126        VariableExpr * funcExpr = new VariableExpr{ loc, decl };
     127        funcExpr->result = new PointerType{ funcExpr->result };
     128        return funcExpr;
    85129}
    86130
     
    108152AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) {
    109153        if ( arg->result ) {
    110                 if ( arg->result->is_lvalue() ) {
     154                if ( arg->get_lvalue() ) {
    111155                        // lvalue, retains all levels of reference, and gains a pointer inside the references
    112156                        Type * res = addrType( arg->result );
    113                         res->set_lvalue( false ); // result of & is never an lvalue
    114157                        result = res;
    115158                } else {
     
    118161                                        dynamic_cast< const ReferenceType * >( arg->result.get() ) ) {
    119162                                Type * res = addrType( refType->base );
    120                                 res->set_lvalue( false ); // result of & is never an lvalue
    121163                                result = res;
    122164                        } else {
     
    139181: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
    140182
     183bool CastExpr::get_lvalue() const {
     184        // This is actually wrong by C, but it works with our current set-up.
     185        return arg->get_lvalue();
     186}
     187
    141188// --- KeywordCastExpr
    142189
    143190const char * KeywordCastExpr::targetString() const {
    144191        return AggregateDecl::aggrString( target );
     192}
     193
     194// --- UntypedMemberExpr
     195
     196bool UntypedMemberExpr::get_lvalue() const {
     197        return aggregate->get_lvalue();
    145198}
    146199
     
    153206        assert( aggregate->result );
    154207
    155         // take ownership of member type
    156208        result = mem->get_type();
     209
    157210        // substitute aggregate generic parameters into member type
    158211        genericSubstitution( aggregate->result ).apply( result );
    159         // ensure lvalue and appropriate restrictions from aggregate type
    160         add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue );
    161 }
    162 
    163 // --- VariableExpr
    164 
    165 VariableExpr::VariableExpr( const CodeLocation & loc )
    166 : Expr( loc ), var( nullptr ) {}
    167 
    168 VariableExpr::VariableExpr( const CodeLocation & loc, const DeclWithType * v )
    169 : Expr( loc ), var( v ) {
    170         assert( var );
    171         assert( var->get_type() );
    172         result = var->get_type();
    173         add_qualifiers( result, CV::Lvalue );
    174 }
    175 
    176 VariableExpr * VariableExpr::functionPointer(
    177                 const CodeLocation & loc, const FunctionDecl * decl ) {
    178         // wrap usually-determined result type in a pointer
    179         VariableExpr * funcExpr = new VariableExpr{ loc, decl };
    180         funcExpr->result = new PointerType{ funcExpr->result };
    181         return funcExpr;
     212        // ensure appropriate restrictions from aggregate type
     213        add_qualifiers( result, aggregate->result->qualifiers );
     214}
     215
     216MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
     217    MemberExpr::NoOpConstruction overloadSelector )
     218: Expr( loc ), member( mem ), aggregate( agg ) {
     219        assert( member );
     220        assert( aggregate );
     221        assert( aggregate->result );
     222        (void) overloadSelector;
     223}
     224
     225bool MemberExpr::get_lvalue() const {
     226        // This is actually wrong by C, but it works with our current set-up.
     227        return true;
    182228}
    183229
     
    258304: Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
    259305
     306// --- CommaExpr
     307bool CommaExpr::get_lvalue() const {
     308        // This is wrong by C, but the current implementation uses it.
     309        // (ex: Specialize, Lvalue and Box)
     310        return arg2->get_lvalue();
     311}
     312
    260313// --- ConstructorExpr
    261314
     
    276329        assert( t && i );
    277330        result = t;
    278         add_qualifiers( result, CV::Lvalue );
     331}
     332
     333bool CompoundLiteralExpr::get_lvalue() const {
     334        return true;
    279335}
    280336
     
    293349        // like MemberExpr, TupleIndexExpr is always an lvalue
    294350        result = type->types[ index ];
    295         add_qualifiers( result, CV::Lvalue );
     351}
     352
     353bool TupleIndexExpr::get_lvalue() const {
     354        return tuple->get_lvalue();
    296355}
    297356
  • src/AST/Expr.hpp

    r3c64c668 r58fe85a  
    3131
    3232// Must be included in *all* AST classes; should be #undef'd at the end of the file
    33 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     33#define MUTATE_FRIEND \
     34    template<typename node_t> friend node_t * mutate(const node_t * node); \
     35        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     36
    3437
    3538class ConverterOldToNew;
     
    4245struct ParamEntry {
    4346        UniqueId decl;
    44         ptr<Decl> declptr;
     47        readonly<Decl> declptr;
    4548        ptr<Type> actualType;
    4649        ptr<Type> formalType;
     
    6265class Expr : public ParseNode {
    6366public:
    64         /// Saves space (~16 bytes) by combining ResnSlots and InferredParams
     67        /*
     68         * NOTE: the union approach is incorrect until the case of
     69         * partial resolution in InferMatcher is eliminated.
     70         * it is reverted to allow unresolved and resolved parameters
     71         * to coexist in an expression node.
     72         */
    6573        struct InferUnion {
     74                // mode is now unused
    6675                enum { Empty, Slots, Params } mode;
    67                 union data_t {
    68                         char def;
    69                         ResnSlots resnSlots;
    70                         InferredParams inferParams;
    71 
    72                         data_t() : def('\0') {}
    73                         ~data_t() {}
     76                struct data_t {
     77                        // char def;
     78                        ResnSlots * resnSlots;
     79                        InferredParams * inferParams;
     80
     81                        data_t(): resnSlots(nullptr), inferParams(nullptr) {}
     82                        data_t(const data_t &other) = delete;
     83                        ~data_t() {
     84                                delete resnSlots;
     85                                delete inferParams;
     86                        }
    7487                } data;
    7588
    7689                /// initializes from other InferUnion
    7790                void init_from( const InferUnion& o ) {
    78                         switch ( o.mode ) {
    79                         case Empty:  return;
    80                         case Slots:  new(&data.resnSlots) ResnSlots{ o.data.resnSlots }; return;
    81                         case Params: new(&data.inferParams) InferredParams{ o.data.inferParams }; return;
     91                        if (o.data.resnSlots) {
     92                                data.resnSlots = new ResnSlots(*o.data.resnSlots);
     93                        }
     94                        if (o.data.inferParams) {
     95                                data.inferParams = new InferredParams(*o.data.inferParams);
    8296                        }
    8397                }
     
    8599                /// initializes from other InferUnion (move semantics)
    86100                void init_from( InferUnion&& o ) {
    87                         switch ( o.mode ) {
    88                         case Empty:  return;
    89                         case Slots:  new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return;
    90                         case Params:
    91                                 new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return;
    92                         }
    93                 }
    94 
    95                 /// clears variant fields
    96                 void reset() {
    97                         switch( mode ) {
    98                         case Empty:  return;
    99                         case Slots:  data.resnSlots.~ResnSlots(); return;
    100                         case Params: data.inferParams.~InferredParams(); return;
    101                         }
     101                        data.resnSlots = o.data.resnSlots;
     102                        data.inferParams = o.data.inferParams;
     103                        o.data.resnSlots = nullptr;
     104                        o.data.inferParams = nullptr;
    102105                }
    103106
     
    107110                InferUnion& operator= ( const InferUnion& ) = delete;
    108111                InferUnion& operator= ( InferUnion&& ) = delete;
    109                 ~InferUnion() { reset(); }
     112
     113                bool hasSlots() const { return data.resnSlots; }
     114                bool hasParams() const { return data.inferParams; }
    110115
    111116                ResnSlots& resnSlots() {
    112                         switch (mode) {
    113                         case Empty: new(&data.resnSlots) ResnSlots{}; mode = Slots; // fallthrough
    114                         case Slots: return data.resnSlots;
    115                         case Params: assertf(false, "Cannot return to resnSlots from Params"); abort();
     117                        if (!data.resnSlots) {
     118                                data.resnSlots = new ResnSlots();
    116119                        }
    117                         assertf(false, "unreachable");
     120                        return *data.resnSlots;
    118121                }
    119122
    120123                const ResnSlots& resnSlots() const {
    121                         if (mode == Slots) {
    122                                 return data.resnSlots;
     124                        if (data.resnSlots) {
     125                                return *data.resnSlots;
    123126                        }
    124127                        assertf(false, "Mode was not already resnSlots");
     
    127130
    128131                InferredParams& inferParams() {
    129                         switch (mode) {
    130                         case Slots: data.resnSlots.~ResnSlots(); // fallthrough
    131                         case Empty: new(&data.inferParams) InferredParams{}; mode = Params; // fallthrough
    132                         case Params: return data.inferParams;
     132                        if (!data.inferParams) {
     133                                data.inferParams = new InferredParams();
    133134                        }
    134                         assertf(false, "unreachable");
     135                        return *data.inferParams;
    135136                }
    136137
    137138                const InferredParams& inferParams() const {
    138                         if (mode == Params) {
    139                                 return data.inferParams;
     139                        if (data.inferParams) {
     140                                return *data.inferParams;
    140141                        }
    141142                        assertf(false, "Mode was not already Params");
     
    143144                }
    144145
    145                 void set_inferParams( InferredParams && ps ) {
    146                         switch(mode) {
    147                         case Slots:
    148                                 data.resnSlots.~ResnSlots();
    149                                 // fallthrough
    150                         case Empty:
    151                                 new(&data.inferParams) InferredParams{ std::move( ps ) };
    152                                 mode = Params;
    153                                 break;
    154                         case Params:
    155                                 data.inferParams = std::move( ps );
    156                                 break;
    157                         }
     146                void set_inferParams( InferredParams * ps ) {
     147                        delete data.resnSlots;
     148                        data.resnSlots = nullptr;
     149                        delete data.inferParams;
     150                        data.inferParams = ps;
    158151                }
    159152
     
    161154                /// and the other is in `Params`.
    162155                void splice( InferUnion && o ) {
    163                         if ( o.mode == Empty ) return;
    164                         if ( mode == Empty ) { init_from( o ); return; }
    165                         assert( mode == o.mode && "attempt to splice incompatible InferUnion" );
    166 
    167                         if ( mode == Slots ){
    168                                 data.resnSlots.insert(
    169                                         data.resnSlots.end(), o.data.resnSlots.begin(), o.data.resnSlots.end() );
    170                         } else if ( mode == Params ) {
    171                                 for ( const auto & p : o.data.inferParams ) {
    172                                         data.inferParams[p.first] = std::move(p.second);
     156                        if (o.data.resnSlots) {
     157                                if (data.resnSlots) {
     158                                        data.resnSlots->insert(
     159                                                data.resnSlots->end(), o.data.resnSlots->begin(), o.data.resnSlots->end() );
     160                                        delete o.data.resnSlots;
    173161                                }
    174                         } else assertf(false, "invalid mode");
     162                                else {
     163                                        data.resnSlots = o.data.resnSlots;
     164                                }
     165                                o.data.resnSlots = nullptr;
     166                        }
     167
     168                        if (o.data.inferParams) {
     169                                if (data.inferParams) {
     170                                        for ( const auto & p : *o.data.inferParams ) {
     171                                                (*data.inferParams)[p.first] = std::move(p.second);
     172                                        }
     173                                        delete o.data.inferParams;
     174                                }
     175                                else {
     176                                        data.inferParams = o.data.inferParams;
     177                                }
     178                                o.data.inferParams = nullptr;
     179                        }
    175180                }
    176181        };
     
    185190
    186191        Expr * set_extension( bool ex ) { extension = ex; return this; }
     192        virtual bool get_lvalue() const;
    187193
    188194        virtual const Expr * accept( Visitor & v ) const override = 0;
     
    201207        ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} );
    202208
     209        bool get_lvalue() const final;
     210
    203211        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    204212private:
     
    216224        : Expr( loc ), func( f ), args( std::move(as) ) {}
    217225
     226        bool get_lvalue() const final;
     227
    218228        /// Creates a new dereference expression
    219         static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg );
     229        static UntypedExpr * createDeref( const CodeLocation & loc, const Expr * arg );
    220230        /// Creates a new assignment expression
    221         static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs );
     231        static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs );
    222232
    223233        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    241251};
    242252
     253/// A reference to a named variable.
     254class VariableExpr final : public Expr {
     255public:
     256        readonly<DeclWithType> var;
     257
     258        VariableExpr( const CodeLocation & loc );
     259        VariableExpr( const CodeLocation & loc, const DeclWithType * v );
     260
     261        bool get_lvalue() const final;
     262
     263        /// generates a function pointer for a given function
     264        static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl );
     265
     266        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     267private:
     268        VariableExpr * clone() const override { return new VariableExpr{ *this }; }
     269        MUTATE_FRIEND
     270};
     271
    243272/// Address-of expression `&e`
    244273class AddressExpr final : public Expr {
     
    271300};
    272301
    273 /// Whether a cast existed in the program source or not
     302/// Inidicates whether the cast is introduced by the CFA type system.
     303/// GeneratedCast for casts that the resolver introduces to force a return type
     304/// ExplicitCast for casts from user code
     305/// ExplicitCast for casts from desugaring advanced CFA features into simpler CFA
     306/// example
     307///   int * p;     // declaration
     308///   (float *) p; // use, with subject cast
     309/// subject cast being GeneratedCast means we are considering an interpretation with a type mismatch
     310/// subject cast being ExplicitCast means someone in charge wants it that way
    274311enum GeneratedFlag { ExplicitCast, GeneratedCast };
    275312
     
    291328        CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {}
    292329
     330        bool get_lvalue() const final;
     331
    293332        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    294333private:
     
    301340public:
    302341        ptr<Expr> arg;
     342        struct Concrete {
     343                std::string field;
     344                std::string getter;
     345
     346                Concrete() = default;
     347                Concrete(const Concrete &) = default;
     348        };
    303349        ast::AggregateDecl::Aggregate target;
     350        Concrete concrete_target;
     351
    304352
    305353        KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t )
    306354        : Expr( loc ), arg( a ), target( t ) {}
    307355
     356        KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t, const Concrete & ct )
     357        : Expr( loc ), arg( a ), target( t ), concrete_target( ct ) {}
     358
    308359        /// Get a name for the target type
    309360        const char * targetString() const;
     
    338389        : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); }
    339390
     391        bool get_lvalue() const final;
     392
    340393        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    341394private:
     
    352405        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg );
    353406
     407        bool get_lvalue() const final;
     408
    354409        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    355410private:
    356411        MemberExpr * clone() const override { return new MemberExpr{ *this }; }
    357412        MUTATE_FRIEND
    358 };
    359 
    360 /// A reference to a named variable.
    361 class VariableExpr final : public Expr {
    362 public:
    363         readonly<DeclWithType> var;
    364 
    365         VariableExpr( const CodeLocation & loc );
    366         VariableExpr( const CodeLocation & loc, const DeclWithType * v );
    367 
    368         /// generates a function pointer for a given function
    369         static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl );
    370 
    371         const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    372 private:
    373         VariableExpr * clone() const override { return new VariableExpr{ *this }; }
    374         MUTATE_FRIEND
     413
     414        // Custructor overload meant only for AST conversion
     415        enum NoOpConstruction { NoOpConstructionChosen };
     416        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
     417            NoOpConstruction overloadSelector );
     418        friend class ::ConverterOldToNew;
     419        friend class ::ConverterNewToOld;
    375420};
    376421
     
    386431                const CodeLocation & loc, const Type * ty, const std::string & r,
    387432                        std::optional<unsigned long long> i )
    388         : Expr( loc, ty ), rep( r ), ival( i ) {}
     433        : Expr( loc, ty ), rep( r ), ival( i ), underlyer(ty) {}
    389434
    390435        /// Gets the integer value of this constant, if one is appropriate to its type.
     
    532577
    533578        CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 )
    534         : Expr( loc ), arg1( a1 ), arg2( a2 ) {}
     579        : Expr( loc ), arg1( a1 ), arg2( a2 ) {
     580                this->result = a2->result;
     581        }
     582
     583        bool get_lvalue() const final;
    535584
    536585        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    577626
    578627        ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call )
    579         : Expr( loc, call->result ) { assert( call ); }
     628        : Expr( loc, call->result ), callExpr(call) { assert( call ); assert(call->result); }
    580629
    581630        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    605654        CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i );
    606655
     656        bool get_lvalue() const final;
     657
    607658        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    608659private:
     
    660711
    661712        TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i );
     713
     714        bool get_lvalue() const final;
    662715
    663716        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    698751        std::vector<ptr<Expr>> dtors;              ///< destructor(s) for return variable(s)
    699752
     753        readonly<ExprStmt> resultExpr;
     754
    700755        StmtExpr( const CodeLocation & loc, const CompoundStmt * ss );
    701756
  • src/AST/Fwd.hpp

    r3c64c668 r58fe85a  
    1010// Created On       : Wed May  8 16:05:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun 24 09:48:00 2019
    13 // Update Count     : 1
     12// Last Modified On : Thr Jul 23 14:15:00 2020
     13// Update Count     : 2
    1414//
    1515
     
    5353class CatchStmt;
    5454class FinallyStmt;
     55class SuspendStmt;
    5556class WaitForStmt;
    5657class WithStmt;
     
    106107class QualifiedType;
    107108class FunctionType;
    108 class ReferenceToType;
    109 class StructInstType;
    110 class UnionInstType;
    111 class EnumInstType;
     109class BaseInstType;
     110template<typename decl_t> class SueInstType;
     111using StructInstType = SueInstType<StructDecl>;
     112using UnionInstType = SueInstType<UnionDecl>;
     113using EnumInstType = SueInstType<EnumDecl>;
    112114class TraitInstType;
    113115class TypeInstType;
     
    135137typedef unsigned int UniqueId;
    136138
     139struct TranslationUnit;
     140// TODO: Get from the TranslationUnit:
     141extern ptr<Type> sizeType;
     142extern const FunctionDecl * dereferenceOperator;
     143extern const StructDecl   * dtorStruct;
     144extern const FunctionDecl * dtorStructDestroy;
     145
    137146}
  • src/AST/GenericSubstitution.cpp

    r3c64c668 r58fe85a  
    4242        private:
    4343                // make substitution for generic type
    44                 void makeSub( const ReferenceToType * ty ) {
     44                void makeSub( const BaseInstType * ty ) {
    4545                        visit_children = false;
    4646                        const AggregateDecl * aggr = ty->aggr();
     
    6262        Pass<GenericSubstitutionBuilder> builder;
    6363        maybe_accept( ty, builder );
    64         return std::move(builder.pass.sub);
     64        return std::move(builder.core.sub);
    6565}
    6666
  • src/AST/Init.hpp

    r3c64c668 r58fe85a  
    2525
    2626// Must be included in *all* AST classes; should be #undef'd at the end of the file
    27 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     27#define MUTATE_FRIEND \
     28    template<typename node_t> friend node_t * mutate(const node_t * node); \
     29        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    2830
    2931namespace ast {
     
    4850
    4951/// Flag for whether to construct from initialzier
    50 enum ConstructFlag { DoConstruct, MaybeConstruct };
     52enum ConstructFlag { NoConstruct, MaybeConstruct };
    5153
    5254/// Object initializer base class
     
    6971        ptr<Expr> value;
    7072
    71         SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = DoConstruct )
     73        SingleInit( const CodeLocation & loc, const Expr * val, ConstructFlag mc = NoConstruct )
    7274        : Init( loc, mc ), value( val ) {}
    7375
     
    8890
    8991        ListInit( const CodeLocation & loc, std::vector<ptr<Init>> && is,
    90                 std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = DoConstruct );
     92                std::vector<ptr<Designation>> && ds = {}, ConstructFlag mc = NoConstruct );
    9193
    9294        using iterator = std::vector<ptr<Init>>::iterator;
     
    116118        ConstructorInit(
    117119                const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init )
    118         : Init( loc, DoConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
     120        : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
    119121
    120122        const Init * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Node.cpp

    r3c64c668 r58fe85a  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 16 14:16:00 2019
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Jun  5 10:21:00 2020
     13// Update Count     : 1
    1414//
    1515
     
    1717#include "Fwd.hpp"
    1818
     19#include <csignal>  // MEMORY DEBUG -- for raise
    1920#include <iostream>
    2021
     
    2930#include "Print.hpp"
    3031
    31 template< typename node_t, enum ast::Node::ref_type ref_t >
    32 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
    33 
    34 template< typename node_t, enum ast::Node::ref_type ref_t >
    35 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
    36 
    37 template< typename node_t, enum ast::Node::ref_type ref_t >
    38 void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
     32/// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object.
     33/// Process to use in GDB:
     34///   break ast::Node::_trap()
     35///   run
     36///   set variable MEM_TRAP_OBJ = <target>
     37///   disable <first breakpoint>
     38///   continue
     39void * MEM_TRAP_OBJ = nullptr;
     40
     41void _trap( const void * node ) {
     42        if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP);
     43}
     44
     45[[noreturn]] static inline void strict_fail(const ast::Node * node) {
     46        assertf(node, "strict_as had nullptr input.");
     47        const ast::ParseNode * parse = dynamic_cast<const ast::ParseNode *>( node );
     48        if ( nullptr == parse ) {
     49                assertf(nullptr, "%s (no location)", toString(node).c_str());
     50        } else if ( parse->location.isUnset() ) {
     51                assertf(nullptr, "%s (unset location)", toString(node).c_str());
     52        } else {
     53                assertf(nullptr, "%s (at %s:%d)", toString(node).c_str(),
     54                        parse->location.filename.c_str(), parse->location.first_line);
     55        }
     56}
     57
     58template< typename node_t, enum ast::Node::ref_type ref_t >
     59void ast::ptr_base<node_t, ref_t>::_strict_fail() const {
     60        strict_fail(node);
     61}
     62
     63template< typename node_t, enum ast::Node::ref_type ref_t >
     64void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
     65        node->increment(ref_t);
     66        _trap( node );
     67}
     68
     69template< typename node_t, enum ast::Node::ref_type ref_t >
     70void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) {
     71        _trap( node );
     72        node->decrement( ref_t, do_delete );
     73}
     74
     75template< typename node_t, enum ast::Node::ref_type ref_t >
     76void ast::ptr_base<node_t, ref_t>::_check() const {
     77        // if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
     78}
    3979
    4080template< typename node_t, enum ast::Node::ref_type ref_t >
     
    226266template class ast::ptr_base< ast::FunctionType, ast::Node::ref_type::weak >;
    227267template class ast::ptr_base< ast::FunctionType, ast::Node::ref_type::strong >;
    228 template class ast::ptr_base< ast::ReferenceToType, ast::Node::ref_type::weak >;
    229 template class ast::ptr_base< ast::ReferenceToType, ast::Node::ref_type::strong >;
     268template class ast::ptr_base< ast::BaseInstType, ast::Node::ref_type::weak >;
     269template class ast::ptr_base< ast::BaseInstType, ast::Node::ref_type::strong >;
    230270template class ast::ptr_base< ast::StructInstType, ast::Node::ref_type::weak >;
    231271template class ast::ptr_base< ast::StructInstType, ast::Node::ref_type::strong >;
  • src/AST/Node.hpp

    r3c64c668 r58fe85a  
    1010// Created On       : Wed May 8 10:27:04 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun  3 13:26:00 2019
    13 // Update Count     : 5
     12// Last Modified On : Fri Jun 5 9:47:00 2020
     13// Update Count     : 6
    1414//
    1515
     
    3838        Node& operator= (const Node&) = delete;
    3939        Node& operator= (Node&&) = delete;
    40         virtual ~Node() = default;
     40        virtual ~Node() {}
    4141
    4242        virtual const Node * accept( Visitor & v ) const = 0;
     
    4949
    5050        bool unique() const { return strong_count == 1; }
     51        bool isManaged() const {return strong_count > 0; }
    5152
    5253private:
     
    5758        template<typename node_t>
    5859        friend node_t * mutate(const node_t * node);
     60        template<typename node_t>
     61        friend node_t * shallowCopy(const node_t * node);
    5962
    6063        mutable size_t strong_count = 0;
     
    6972        }
    7073
    71         void decrement(ast::Node::ref_type ref) const {
     74        void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
    7275                switch (ref) {
    7376                        case ref_type::strong: strong_count--; break;
     
    7578                }
    7679
    77                 if(!strong_count && !weak_count) {
     80                if( do_delete && !strong_count && !weak_count) {
    7881                        delete this;
    7982                }
     
    9497        assertf(
    9598                node->weak_count == 0,
    96                 "Error: mutating node with weak references to it will invalided some references"
     99                "Error: mutating node with weak references to it will invalidate some references"
    97100        );
    98101        return node->clone();
     
    104107        // skip mutate if equivalent
    105108        if ( node->*field == val ) return node;
    106        
     109
    107110        // mutate and return
    108111        node_t * ret = mutate( node );
     
    123126        (ret->*field)[i] = std::forward< field_t >( val );
    124127        return ret;
     128}
     129
     130/// Mutate an entire indexed collection by cloning to accepted value
     131template<typename node_t, typename parent_t, typename coll_t>
     132const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) {
     133        for ( unsigned i = 0; i < (node->*field).size(); ++i ) {
     134                node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) );
     135        }
     136        return node;
    125137}
    126138
     
    217229        const node_t & operator* () const { _check(); return *node; }
    218230        explicit operator bool() const { _check(); return node; }
    219         operator const node_t * () const { _check(); return node; }
     231        operator const node_t * () const & { _check(); return node; }
     232        operator const node_t * () && = delete;
     233
     234        const node_t * release() {
     235                const node_t * ret = node;
     236                if ( node ) {
     237                        _dec(node, false);
     238                        node = nullptr;
     239                }
     240                return ret;
     241        }
    220242
    221243        /// wrapper for convenient access to dynamic_cast
     
    223245        const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); }
    224246
    225         /// wrapper for convenient access to strict_dynamic_cast
     247        /// Wrapper that makes sure dynamic_cast returns non-null.
    226248        template<typename o_node_t>
    227         const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); }
     249        const o_node_t * strict_as() const {
     250                if (const o_node_t * ret = as<o_node_t>()) return ret;
     251                _strict_fail();
     252        }
     253
     254        /// Wrapper that makes sure dynamic_cast does not fail.
     255        template<typename o_node_t, decltype(nullptr) null>
     256        const o_node_t * strict_as() const { return node ? strict_as<o_node_t>() : nullptr; }
    228257
    229258        /// Returns a mutable version of the pointer in this node.
     
    244273
    245274        void _inc( const node_t * other );
    246         void _dec( const node_t * other );
     275        void _dec( const node_t * other, bool do_delete = true );
    247276        void _check() const;
     277        void _strict_fail() const __attribute__((noreturn));
    248278
    249279        const node_t * node;
  • src/AST/Pass.hpp

    r3c64c668 r58fe85a  
    88//
    99// Author           : Thierry Delisle
    10 // Created On       : Thu May 09 15::37::05 2019
     10// Created On       : Thu May 09 15:37:05 2019
    1111// Last Modified By :
    1212// Last Modified On :
     
    4646//
    4747// Several additional features are available through inheritance
    48 // | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
    49 //                          current expression
    50 // | WithStmtsToAdd       - provides the ability to insert statements before or after the current
    51 //                          statement by adding new statements into stmtsToAddBefore or
    52 //                          stmtsToAddAfter respectively.
    53 // | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
    54 //                          declarations by adding new DeclStmt into declsToAddBefore or
    55 //                          declsToAddAfter respectively.
    56 // | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
    57 //                          to false in pre{visit,visit} to skip visiting children
    58 // | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
    59 //                          call GuardValue with the variable to save, the variable will
    60 //                          automatically be restored to its previous value after the corresponding
    61 //                          postvisit/postmutate teminates.
    62 // | WithVisitorRef       - provides an pointer to the templated visitor wrapper
    63 // | WithSymbolTable      - provides symbol table functionality
     48// | PureVisitor           - makes the visitor pure, it never modifies nodes in place and always
     49//                           clones nodes it needs to make changes to
     50// | WithConstTypeSubstitution - provides polymorphic const TypeSubstitution * typeSubs for the
     51//                           current expression
     52// | WithStmtsToAdd        - provides the ability to insert statements before or after the current
     53//                           statement by adding new statements into stmtsToAddBefore or
     54//                           stmtsToAddAfter respectively.
     55// | WithDeclsToAdd        - provides the ability to insert declarations before or after the
     56//                           current declarations by adding new DeclStmt into declsToAddBefore or
     57//                           declsToAddAfter respectively.
     58// | WithShortCircuiting   - provides the ability to skip visiting child nodes; set visit_children
     59//                           to false in pre{visit,visit} to skip visiting children
     60// | WithGuards            - provides the ability to save/restore data like a LIFO stack; to save,
     61//                           call GuardValue with the variable to save, the variable will
     62//                           automatically be restored to its previous value after the
     63//                           corresponding postvisit/postmutate teminates.
     64// | WithVisitorRef        - provides an pointer to the templated visitor wrapper
     65// | WithSymbolTable       - provides symbol table functionality
     66//
     67// Other Special Members:
     68// | result                - Either a method that takes no parameters or a field. If a method (or
     69//                           callable field) get_result calls it, otherwise the value is returned.
    6470//-------------------------------------------------------------------------------------------------
    65 template< typename pass_t >
     71template< typename core_t >
    6672class Pass final : public ast::Visitor {
    6773public:
     74        using core_type = core_t;
     75        using type = Pass<core_t>;
     76
    6877        /// Forward any arguments to the pass constructor
    6978        /// Propagate 'this' if necessary
    7079        template< typename... Args >
    7180        Pass( Args &&... args)
    72                 : pass( std::forward<Args>( args )... )
     81                : core( std::forward<Args>( args )... )
    7382        {
    7483                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    75                 typedef Pass<pass_t> this_t;
    76                 this_t * const * visitor = __pass::visitor(pass, 0);
     84                type * const * visitor = __pass::visitor(core, 0);
    7785                if(visitor) {
    78                         *const_cast<this_t **>( visitor ) = this;
     86                        *const_cast<type **>( visitor ) = this;
    7987                }
    8088        }
     
    8290        virtual ~Pass() = default;
    8391
    84         /// Storage for the actual pass
    85         pass_t pass;
     92        /// Storage for the actual pass.
     93        core_t core;
     94
     95        /// If the core defines a result, call it if possible, otherwise return it.
     96        inline auto get_result() -> decltype( __pass::get_result( core, '0' ) ) {
     97                return __pass::get_result( core, '0' );
     98        }
     99
     100        /// Construct and run a pass on a translation unit.
     101        template< typename... Args >
     102        static void run( TranslationUnit & decls, Args &&... args ) {
     103                Pass<core_t> visitor( std::forward<Args>( args )... );
     104                accept_all( decls, visitor );
     105        }
     106
     107        /// Contruct and run a pass on a pointer to extract a value.
     108        template< typename node_type, typename... Args >
     109        static auto read( node_type const * node, Args&&... args ) {
     110                Pass<core_t> visitor( std::forward<Args>( args )... );
     111                node_type const * temp = node->accept( visitor );
     112                assert( temp == node );
     113                return visitor.get_result();
     114        }
     115
     116        // Versions of the above for older compilers.
     117        template< typename... Args >
     118        static void run( TranslationUnit & decls ) {
     119                Pass<core_t> visitor;
     120                accept_all( decls, visitor );
     121        }
     122
     123        template< typename node_type, typename... Args >
     124        static auto read( node_type const * node ) {
     125                Pass<core_t> visitor;
     126                node_type const * temp = node->accept( visitor );
     127                assert( temp == node );
     128                return visitor.get_result();
     129        }
    86130
    87131        /// Visit function declarations
     
    111155        const ast::Stmt *             visit( const ast::CatchStmt            * ) override final;
    112156        const ast::Stmt *             visit( const ast::FinallyStmt          * ) override final;
     157        const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
    113158        const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
    114159        const ast::Decl *             visit( const ast::WithStmt             * ) override final;
     
    178223        const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
    179224
    180         template<typename pass_type>
    181         friend void accept_all( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor );
     225        template<typename core_type>
     226        friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
     227
     228        bool isInFunction() const {
     229                return inFunction;
     230        }
     231
    182232private:
    183233
    184         bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
     234        bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; }
    185235
    186236private:
    187237        const ast::Stmt * call_accept( const ast::Stmt * );
    188238        const ast::Expr * call_accept( const ast::Expr * );
     239
     240        // requests WithStmtsToAdd directly add to this statement, as if it is a compound.
     241
     242        const ast::Stmt * call_accept_as_compound(const ast::Stmt *);
    189243
    190244        template< typename node_t >
     
    206260        void maybe_accept(const node_t * &, child_t parent_t::* child);
    207261
     262        template<typename node_t, typename parent_t, typename child_t>
     263        void maybe_accept_as_compound(const node_t * &, child_t parent_t::* child);
     264
    208265private:
    209266        /// Internal RAII guard for symbol table features
    210267        struct guard_symtab {
    211                 guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }
    212                 ~guard_symtab()                                   { __pass::symtab::leave(pass, 0); }
    213                 Pass<pass_t> & pass;
     268                guard_symtab( Pass<core_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.core, 0); }
     269                ~guard_symtab()                                   { __pass::symtab::leave(pass.core, 0); }
     270                Pass<core_t> & pass;
    214271        };
    215272
    216273        /// Internal RAII guard for scope features
    217274        struct guard_scope {
    218                 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
    219                 ~guard_scope()                                   { __pass::scope::leave(pass, 0); }
    220                 Pass<pass_t> & pass;
     275                guard_scope( Pass<core_t> & pass ): pass( pass ) { __pass::scope::enter(pass.core, 0); }
     276                ~guard_scope()                                   { __pass::scope::leave(pass.core, 0); }
     277                Pass<core_t> & pass;
     278        };
     279
     280        /// Internal RAII guard for forall substitutions
     281        struct guard_forall_subs {
     282                guard_forall_subs( Pass<core_t> & pass, const FunctionType * type )
     283                : pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
     284                ~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
     285                Pass<core_t> & pass;
     286                const FunctionType * type;
    221287        };
    222288
    223289private:
    224290        bool inFunction = false;
     291        bool atFunctionTop = false;
    225292};
    226293
    227294/// Apply a pass to an entire translation unit
    228 template<typename pass_t>
    229 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
     295template<typename core_t>
     296void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
     297
     298template<typename core_t>
     299void accept_all( ast::TranslationUnit &, ast::Pass<core_t> & visitor );
    230300
    231301//-------------------------------------------------------------------------------------------------
     
    233303//-------------------------------------------------------------------------------------------------
    234304
    235 /// Keep track of the polymorphic const TypeSubstitution * env for the current expression
     305/// If used the visitor will always clone nodes.
     306struct PureVisitor {};
     307
     308/// Keep track of the polymorphic const TypeSubstitution * typeSubs for the current expression.
    236309struct WithConstTypeSubstitution {
    237         const TypeSubstitution * env = nullptr;
     310        const TypeSubstitution * typeSubs = nullptr;
    238311};
    239312
     
    267340        };
    268341
    269         template< typename pass_t>
    270         friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );
     342        template< typename core_t>
     343        friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup );
    271344public:
    272345
     
    304377
    305378/// Used to get a pointer to the pass with its wrapped type
    306 template<typename pass_t>
     379template<typename core_t>
    307380struct WithVisitorRef {
    308         Pass<pass_t> * const visitor = nullptr;
     381        Pass<core_t> * const visitor = nullptr;
     382
     383        bool isInFunction() const {
     384                return visitor->isInFunction();
     385        }
    309386};
    310387
     
    313390        SymbolTable symtab;
    314391};
     392
    315393}
    316394
     
    320398extern struct PassVisitorStats {
    321399        size_t depth = 0;
    322         Stats::Counters::MaxCounter<double> * max = nullptr;
    323         Stats::Counters::AverageCounter<double> * avg = nullptr;
     400        Stats::Counters::MaxCounter<double> * max;
     401        Stats::Counters::AverageCounter<double> * avg;
    324402} pass_visitor_stats;
    325403}
  • src/AST/Pass.impl.hpp

    r3c64c668 r58fe85a  
    2020#include <unordered_map>
    2121
     22#include "AST/TranslationUnit.hpp"
    2223#include "AST/TypeSubstitution.hpp"
    2324
     
    2526        using namespace ast; \
    2627        /* back-up the visit children */ \
    27         __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
     28        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \
    2829        /* setup the scope for passes that want to run code at exit */ \
    29         __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
     30        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (core, 0) ); \
     31        /* begin tracing memory allocation if requested by this pass */ \
     32        __pass::beginTrace( core, 0 ); \
    3033        /* call the implementation of the previsit of this pass */ \
    31         __pass::previsit( pass, node, 0 );
     34        __pass::previsit( core, node, 0 );
    3235
    3336#define VISIT( code... ) \
     
    4043#define VISIT_END( type, node ) \
    4144        /* call the implementation of the postvisit of this pass */ \
    42         auto __return = __pass::postvisit( pass, node, 0 ); \
     45        auto __return = __pass::postvisit( core, node, 0 ); \
    4346        assertf(__return, "post visit should never return null"); \
     47        /* end tracing memory allocation if requested by this pass */ \
     48        __pass::endTrace( core, 0 ); \
    4449        return __return;
    4550
     
    5358
    5459namespace ast {
     60        template<typename node_t>
     61        node_t * shallowCopy( const node_t * node );
     62
    5563        namespace __pass {
    5664                // Check if this is either a null pointer or a pointer to an empty container
     
    6068                }
    6169
     70                template< typename core_t, typename node_t >
     71                static inline node_t* mutate(const node_t *node) {
     72                        return std::is_base_of<PureVisitor, core_t>::value ? ::ast::shallowCopy(node) : ::ast::mutate(node);
     73                }
     74
    6275                //------------------------------
    6376                template<typename it_t, template <class...> class container_t>
     
    119132        }
    120133
    121         template< typename pass_t >
     134        template< typename core_t >
    122135        template< typename node_t >
    123         auto ast::Pass< pass_t >::call_accept( const node_t * node )
     136        auto ast::Pass< core_t >::call_accept( const node_t * node )
    124137                -> typename std::enable_if<
    125138                                !std::is_base_of<ast::Expr, node_t>::value &&
     
    127140                        , decltype( node->accept(*this) )
    128141                >::type
    129 
    130142        {
    131143                __pedantic_pass_assert( __visit_children() );
    132                 __pedantic_pass_assert( expr );
     144                __pedantic_pass_assert( node );
    133145
    134146                static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
     
    138150        }
    139151
    140         template< typename pass_t >
    141         const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {
     152        template< typename core_t >
     153        const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
    142154                __pedantic_pass_assert( __visit_children() );
    143155                __pedantic_pass_assert( expr );
    144156
    145                 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
    146                 if ( env_ptr && expr->env ) {
    147                         *env_ptr = expr->env;
     157                const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 );
     158                if ( typeSubs_ptr && expr->env ) {
     159                        *typeSubs_ptr = expr->env;
    148160                }
    149161
     
    151163        }
    152164
    153         template< typename pass_t >
    154         const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
     165        template< typename core_t >
     166        const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
    155167                __pedantic_pass_assert( __visit_children() );
    156168                __pedantic_pass_assert( stmt );
    157169
     170                return stmt->accept( *this );
     171        }
     172
     173        template< typename core_t >
     174        const ast::Stmt * ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) {
     175                __pedantic_pass_assert( __visit_children() );
     176                __pedantic_pass_assert( stmt );
     177
    158178                // add a few useful symbols to the scope
    159179                using __pass::empty;
    160180
    161181                // get the stmts/decls that will need to be spliced in
    162                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    163                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    164                 auto decls_before = __pass::declsToAddBefore( pass, 0);
    165                 auto decls_after  = __pass::declsToAddAfter ( pass, 0);
     182                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     183                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
     184                auto decls_before = __pass::declsToAddBefore( core, 0);
     185                auto decls_after  = __pass::declsToAddAfter ( core, 0);
    166186
    167187                // These may be modified by subnode but most be restored once we exit this statemnet.
    168                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0) );
     188                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::typeSubs( core, 0 ) );
    169189                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    170190                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    202222        }
    203223
    204         template< typename pass_t >
     224        template< typename core_t >
    205225        template< template <class...> class container_t >
    206         container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     226        container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    207227                __pedantic_pass_assert( __visit_children() );
    208228                if( statements.empty() ) return {};
     
    215235
    216236                // get the stmts/decls that will need to be spliced in
    217                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    218                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    219                 auto decls_before = __pass::declsToAddBefore( pass, 0);
    220                 auto decls_after  = __pass::declsToAddAfter ( pass, 0);
     237                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     238                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
     239                auto decls_before = __pass::declsToAddBefore( core, 0);
     240                auto decls_after  = __pass::declsToAddAfter ( core, 0);
    221241
    222242                // These may be modified by subnode but most be restored once we exit this statemnet.
     
    268288        }
    269289
    270         template< typename pass_t >
     290        template< typename core_t >
    271291        template< template <class...> class container_t, typename node_t >
    272         container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     292        container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    273293                __pedantic_pass_assert( __visit_children() );
    274294                if( container.empty() ) return {};
     
    299319        }
    300320
    301         template< typename pass_t >
     321        template< typename core_t >
    302322        template<typename node_t, typename parent_t, typename child_t>
    303         void ast::Pass< pass_t >::maybe_accept(
     323        void ast::Pass< core_t >::maybe_accept(
    304324                const node_t * & parent,
    305325                child_t parent_t::*child
     
    317337
    318338                if( __pass::differs(old_val, new_val) ) {
    319                         auto new_parent = mutate(parent);
     339                        auto new_parent = __pass::mutate<core_t>(parent);
     340                        new_parent->*child = new_val;
     341                        parent = new_parent;
     342                }
     343        }
     344
     345        template< typename core_t >
     346        template<typename node_t, typename parent_t, typename child_t>
     347        void ast::Pass< core_t >::maybe_accept_as_compound(
     348                const node_t * & parent,
     349                child_t parent_t::*child
     350        ) {
     351                static_assert( std::is_base_of<parent_t, node_t>::value, "Error deducing member object" );
     352
     353                if(__pass::skip(parent->*child)) return;
     354                const auto & old_val = __pass::get(parent->*child, 0);
     355
     356                static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
     357
     358                auto new_val = call_accept_as_compound( old_val );
     359
     360                static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
     361
     362                if( __pass::differs(old_val, new_val) ) {
     363                        auto new_parent = __pass::mutate<core_t>(parent);
    320364                        new_parent->*child = new_val;
    321365                        parent = new_parent;
     
    333377//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    334378
    335 template< typename pass_t >
    336 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
     379template< typename core_t >
     380inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) {
    337381        // We are going to aggregate errors for all these statements
    338382        SemanticErrorException errors;
     
    342386
    343387        // get the stmts/decls that will need to be spliced in
    344         auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
    345         auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
     388        auto decls_before = __pass::declsToAddBefore( visitor.core, 0);
     389        auto decls_after  = __pass::declsToAddAfter ( visitor.core, 0);
    346390
    347391        // update pass statitistics
     
    363407                }
    364408                catch( SemanticErrorException &e ) {
    365                         errors.append( e );
     409                        if (__pass::on_error (visitor.core, *i, 0))
     410                                errors.append( e );
    366411                }
    367412
     
    371416        pass_visitor_stats.depth--;
    372417        if ( !errors.isEmpty() ) { throw errors; }
     418}
     419
     420template< typename core_t >
     421inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
     422        return ast::accept_all( unit.decls, visitor );
    373423}
    374424
     
    392442//--------------------------------------------------------------------------
    393443// ObjectDecl
    394 template< typename pass_t >
    395 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
     444template< typename core_t >
     445const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) {
    396446        VISIT_START( node );
    397447
     
    406456        )
    407457
    408         __pass::symtab::addId( pass, 0, node );
     458        __pass::symtab::addId( core, 0, node );
    409459
    410460        VISIT_END( DeclWithType, node );
     
    413463//--------------------------------------------------------------------------
    414464// FunctionDecl
    415 template< typename pass_t >
    416 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
    417         VISIT_START( node );
    418 
    419         __pass::symtab::addId( pass, 0, node );
     465template< typename core_t >
     466const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) {
     467        VISIT_START( node );
     468
     469        __pass::symtab::addId( core, 0, node );
    420470
    421471        VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
     
    425475                // shadow with exprs and not the other way around.
    426476                guard_symtab guard { *this };
    427                 __pass::symtab::addWith( pass, 0, node->withExprs, node );
     477                __pass::symtab::addWith( core, 0, node->withExprs, node );
    428478                {
    429479                        guard_symtab guard { *this };
    430480                        // implicit add __func__ identifier as specified in the C manual 6.4.2.2
    431                         static ast::ObjectDecl func(
    432                                 node->location, "__func__",
    433                                 new ast::ArrayType(
    434                                         new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
     481                        static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{
     482                                CodeLocation{}, "__func__",
     483                                new ast::ArrayType{
     484                                        new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
    435485                                        nullptr, VariableLen, DynamicDim
    436                                 )
    437                         );
    438                         __pass::symtab::addId( pass, 0, &func );
     486                                }
     487                        } };
     488                        __pass::symtab::addId( core, 0, func );
    439489                        VISIT(
    440                                 maybe_accept( node, &FunctionDecl::type );
    441                                 // function body needs to have the same scope as parameters - CompoundStmt will not enter
    442                                 // a new scope if inFunction is true
     490                                // parameter declarations
     491                                maybe_accept( node, &FunctionDecl::params );
     492                                maybe_accept( node, &FunctionDecl::returns );
     493                                // type params and assertions
     494                                maybe_accept( node, &FunctionDecl::type_params );
     495                                maybe_accept( node, &FunctionDecl::assertions );
     496                                // First remember that we are now within a function.
    443497                                ValueGuard< bool > oldInFunction( inFunction );
    444498                                inFunction = true;
     499                                // The function body needs to have the same scope as parameters.
     500                                // A CompoundStmt will not enter a new scope if atFunctionTop is true.
     501                                ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     502                                atFunctionTop = true;
    445503                                maybe_accept( node, &FunctionDecl::stmts );
    446504                                maybe_accept( node, &FunctionDecl::attributes );
     
    454512//--------------------------------------------------------------------------
    455513// StructDecl
    456 template< typename pass_t >
    457 const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
     514template< typename core_t >
     515const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) {
    458516        VISIT_START( node );
    459517
    460518        // make up a forward declaration and add it before processing the members
    461519        // needs to be on the heap because addStruct saves the pointer
    462         __pass::symtab::addStructFwd( pass, 0, node );
     520        __pass::symtab::addStructFwd( core, 0, node );
    463521
    464522        VISIT({
     
    469527
    470528        // this addition replaces the forward declaration
    471         __pass::symtab::addStruct( pass, 0, node );
     529        __pass::symtab::addStruct( core, 0, node );
    472530
    473531        VISIT_END( Decl, node );
     
    476534//--------------------------------------------------------------------------
    477535// UnionDecl
    478 template< typename pass_t >
    479 const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
     536template< typename core_t >
     537const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) {
    480538        VISIT_START( node );
    481539
    482540        // make up a forward declaration and add it before processing the members
    483         __pass::symtab::addUnionFwd( pass, 0, node );
     541        __pass::symtab::addUnionFwd( core, 0, node );
    484542
    485543        VISIT({
     
    489547        })
    490548
    491         __pass::symtab::addUnion( pass, 0, node );
     549        __pass::symtab::addUnion( core, 0, node );
    492550
    493551        VISIT_END( Decl, node );
     
    496554//--------------------------------------------------------------------------
    497555// EnumDecl
    498 template< typename pass_t >
    499 const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
    500         VISIT_START( node );
    501 
    502         __pass::symtab::addEnum( pass, 0, node );
     556template< typename core_t >
     557const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) {
     558        VISIT_START( node );
     559
     560        __pass::symtab::addEnum( core, 0, node );
    503561
    504562        VISIT(
     
    513571//--------------------------------------------------------------------------
    514572// TraitDecl
    515 template< typename pass_t >
    516 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
     573template< typename core_t >
     574const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) {
    517575        VISIT_START( node );
    518576
     
    523581        })
    524582
    525         __pass::symtab::addTrait( pass, 0, node );
     583        __pass::symtab::addTrait( core, 0, node );
    526584
    527585        VISIT_END( Decl, node );
     
    530588//--------------------------------------------------------------------------
    531589// TypeDecl
    532 template< typename pass_t >
    533 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
     590template< typename core_t >
     591const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) {
    534592        VISIT_START( node );
    535593
    536594        VISIT({
    537595                guard_symtab guard { *this };
    538                 maybe_accept( node, &TypeDecl::params );
    539596                maybe_accept( node, &TypeDecl::base   );
    540597        })
     
    543600        // note that assertions come after the type is added to the symtab, since they are not part of the type proper
    544601        // and may depend on the type itself
    545         __pass::symtab::addType( pass, 0, node );
     602        __pass::symtab::addType( core, 0, node );
    546603
    547604        VISIT(
     
    559616//--------------------------------------------------------------------------
    560617// TypedefDecl
    561 template< typename pass_t >
    562 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
     618template< typename core_t >
     619const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) {
    563620        VISIT_START( node );
    564621
    565622        VISIT({
    566623                guard_symtab guard { *this };
    567                 maybe_accept( node, &TypedefDecl::params );
    568624                maybe_accept( node, &TypedefDecl::base   );
    569625        })
    570626
    571         __pass::symtab::addType( pass, 0, node );
     627        __pass::symtab::addType( core, 0, node );
    572628
    573629        VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
     
    578634//--------------------------------------------------------------------------
    579635// AsmDecl
    580 template< typename pass_t >
    581 const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
     636template< typename core_t >
     637const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) {
    582638        VISIT_START( node );
    583639
     
    591647//--------------------------------------------------------------------------
    592648// StaticAssertDecl
    593 template< typename pass_t >
    594 const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
     649template< typename core_t >
     650const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) {
    595651        VISIT_START( node );
    596652
     
    605661//--------------------------------------------------------------------------
    606662// CompoundStmt
    607 template< typename pass_t >
    608 const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
    609         VISIT_START( node );
    610         VISIT({
    611                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    612                 auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
    613                         if ( ! inFunction ) __pass::symtab::enter(pass, 0);
    614                 }, [this, inFunction = this->inFunction]() {
    615                         if ( ! inFunction ) __pass::symtab::leave(pass, 0);
     663template< typename core_t >
     664const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
     665        VISIT_START( node );
     666        VISIT(
     667                // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result.
     668                auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() {
     669                        if ( enterScope ) {
     670                                __pass::symtab::enter(core, 0);
     671                                __pass::scope::enter(core, 0);
     672                        }
     673                }, [this, leaveScope = !this->atFunctionTop]() {
     674                        if ( leaveScope ) {
     675                                __pass::symtab::leave(core, 0);
     676                                __pass::scope::leave(core, 0);
     677                        }
    616678                });
    617                 ValueGuard< bool > guard2( inFunction );
     679                ValueGuard< bool > guard2( atFunctionTop );
     680                atFunctionTop = false;
    618681                guard_scope guard3 { *this };
    619                 inFunction = false;
    620682                maybe_accept( node, &CompoundStmt::kids );
    621         })
     683        )
    622684        VISIT_END( CompoundStmt, node );
    623685}
     
    625687//--------------------------------------------------------------------------
    626688// ExprStmt
    627 template< typename pass_t >
    628 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {
     689template< typename core_t >
     690const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) {
    629691        VISIT_START( node );
    630692
     
    638700//--------------------------------------------------------------------------
    639701// AsmStmt
    640 template< typename pass_t >
    641 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {
     702template< typename core_t >
     703const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) {
    642704        VISIT_START( node )
    643705
     
    654716//--------------------------------------------------------------------------
    655717// DirectiveStmt
    656 template< typename pass_t >
    657 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {
     718template< typename core_t >
     719const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) {
    658720        VISIT_START( node )
    659721
     
    663725//--------------------------------------------------------------------------
    664726// IfStmt
    665 template< typename pass_t >
    666 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
     727template< typename core_t >
     728const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) {
    667729        VISIT_START( node );
    668730
     
    672734                maybe_accept( node, &IfStmt::inits    );
    673735                maybe_accept( node, &IfStmt::cond     );
    674                 maybe_accept( node, &IfStmt::thenPart );
    675                 maybe_accept( node, &IfStmt::elsePart );
     736                maybe_accept_as_compound( node, &IfStmt::thenPart );
     737                maybe_accept_as_compound( node, &IfStmt::elsePart );
    676738        })
    677739
     
    681743//--------------------------------------------------------------------------
    682744// WhileStmt
    683 template< typename pass_t >
    684 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {
     745template< typename core_t >
     746const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) {
    685747        VISIT_START( node );
    686748
     
    690752                maybe_accept( node, &WhileStmt::inits );
    691753                maybe_accept( node, &WhileStmt::cond  );
    692                 maybe_accept( node, &WhileStmt::body  );
     754                maybe_accept_as_compound( node, &WhileStmt::body  );
    693755        })
    694756
     
    698760//--------------------------------------------------------------------------
    699761// ForStmt
    700 template< typename pass_t >
    701 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {
     762template< typename core_t >
     763const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) {
    702764        VISIT_START( node );
    703765
     
    705767                // for statements introduce a level of scope (for the initialization)
    706768                guard_symtab guard { *this };
     769                // xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later.
    707770                maybe_accept( node, &ForStmt::inits );
    708771                maybe_accept( node, &ForStmt::cond  );
    709772                maybe_accept( node, &ForStmt::inc   );
    710                 maybe_accept( node, &ForStmt::body  );
     773                maybe_accept_as_compound( node, &ForStmt::body  );
    711774        })
    712775
     
    716779//--------------------------------------------------------------------------
    717780// SwitchStmt
    718 template< typename pass_t >
    719 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {
     781template< typename core_t >
     782const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) {
    720783        VISIT_START( node );
    721784
     
    730793//--------------------------------------------------------------------------
    731794// CaseStmt
    732 template< typename pass_t >
    733 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {
     795template< typename core_t >
     796const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) {
    734797        VISIT_START( node );
    735798
     
    744807//--------------------------------------------------------------------------
    745808// BranchStmt
    746 template< typename pass_t >
    747 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {
     809template< typename core_t >
     810const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) {
    748811        VISIT_START( node );
    749812        VISIT_END( Stmt, node );
     
    752815//--------------------------------------------------------------------------
    753816// ReturnStmt
    754 template< typename pass_t >
    755 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {
     817template< typename core_t >
     818const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) {
    756819        VISIT_START( node );
    757820
     
    765828//--------------------------------------------------------------------------
    766829// ThrowStmt
    767 template< typename pass_t >
    768 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {
     830template< typename core_t >
     831const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) {
    769832        VISIT_START( node );
    770833
     
    779842//--------------------------------------------------------------------------
    780843// TryStmt
    781 template< typename pass_t >
    782 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {
     844template< typename core_t >
     845const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) {
    783846        VISIT_START( node );
    784847
     
    794857//--------------------------------------------------------------------------
    795858// CatchStmt
    796 template< typename pass_t >
    797 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
     859template< typename core_t >
     860const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) {
    798861        VISIT_START( node );
    799862
     
    803866                maybe_accept( node, &CatchStmt::decl );
    804867                maybe_accept( node, &CatchStmt::cond );
    805                 maybe_accept( node, &CatchStmt::body );
     868                maybe_accept_as_compound( node, &CatchStmt::body );
    806869        })
    807870
     
    811874//--------------------------------------------------------------------------
    812875// FinallyStmt
    813 template< typename pass_t >
    814 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
     876template< typename core_t >
     877const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) {
    815878        VISIT_START( node );
    816879
     
    823886
    824887//--------------------------------------------------------------------------
     888// FinallyStmt
     889template< typename core_t >
     890const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) {
     891        VISIT_START( node );
     892
     893        VISIT(
     894                maybe_accept( node, &SuspendStmt::then   );
     895        )
     896
     897        VISIT_END( Stmt, node );
     898}
     899
     900//--------------------------------------------------------------------------
    825901// WaitForStmt
    826 template< typename pass_t >
    827 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
     902template< typename core_t >
     903const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) {
    828904        VISIT_START( node );
    829905                // for( auto & clause : node->clauses ) {
     
    862938
    863939                if(mutated) {
    864                         auto n = mutate(node);
     940                        auto n = __pass::mutate<core_t>(node);
    865941                        n->clauses = std::move( new_clauses );
    866942                        node = n;
     
    872948                        auto nval = call_accept( node->field ); \
    873949                        if(nval != node->field ) { \
    874                                 auto nparent = mutate(node); \
     950                                auto nparent = __pass::mutate<core_t>(node); \
    875951                                nparent->field = nval; \
    876952                                node = nparent; \
     
    893969//--------------------------------------------------------------------------
    894970// WithStmt
    895 template< typename pass_t >
    896 const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
     971template< typename core_t >
     972const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) {
    897973        VISIT_START( node );
    898974
     
    902978                        // catch statements introduce a level of scope (for the caught exception)
    903979                        guard_symtab guard { *this };
    904                         __pass::symtab::addWith( pass, 0, node->exprs, node );
     980                        __pass::symtab::addWith( core, 0, node->exprs, node );
    905981                        maybe_accept( node, &WithStmt::stmt );
    906982                }
     
    911987//--------------------------------------------------------------------------
    912988// NullStmt
    913 template< typename pass_t >
    914 const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
     989template< typename core_t >
     990const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) {
    915991        VISIT_START( node );
    916992        VISIT_END( NullStmt, node );
     
    919995//--------------------------------------------------------------------------
    920996// DeclStmt
    921 template< typename pass_t >
    922 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
     997template< typename core_t >
     998const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) {
    923999        VISIT_START( node );
    9241000
     
    9321008//--------------------------------------------------------------------------
    9331009// ImplicitCtorDtorStmt
    934 template< typename pass_t >
    935 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
     1010template< typename core_t >
     1011const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
    9361012        VISIT_START( node );
    9371013
    9381014        // For now this isn't visited, it is unclear if this causes problem
    9391015        // if all tests are known to pass, remove this code
    940         // VISIT(
    941         //      maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
    942         // )
     1016        VISIT(
     1017                maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
     1018        )
    9431019
    9441020        VISIT_END( Stmt, node );
     
    9471023//--------------------------------------------------------------------------
    9481024// ApplicationExpr
    949 template< typename pass_t >
    950 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {
     1025template< typename core_t >
     1026const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) {
    9511027        VISIT_START( node );
    9521028
     
    9651041//--------------------------------------------------------------------------
    9661042// UntypedExpr
    967 template< typename pass_t >
    968 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {
     1043template< typename core_t >
     1044const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) {
    9691045        VISIT_START( node );
    9701046
     
    9831059//--------------------------------------------------------------------------
    9841060// NameExpr
    985 template< typename pass_t >
    986 const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {
     1061template< typename core_t >
     1062const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) {
    9871063        VISIT_START( node );
    9881064
     
    9971073//--------------------------------------------------------------------------
    9981074// CastExpr
    999 template< typename pass_t >
    1000 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {
     1075template< typename core_t >
     1076const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) {
    10011077        VISIT_START( node );
    10021078
     
    10131089//--------------------------------------------------------------------------
    10141090// KeywordCastExpr
    1015 template< typename pass_t >
    1016 const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {
     1091template< typename core_t >
     1092const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) {
    10171093        VISIT_START( node );
    10181094
     
    10291105//--------------------------------------------------------------------------
    10301106// VirtualCastExpr
    1031 template< typename pass_t >
    1032 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {
     1107template< typename core_t >
     1108const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) {
    10331109        VISIT_START( node );
    10341110
     
    10451121//--------------------------------------------------------------------------
    10461122// AddressExpr
    1047 template< typename pass_t >
    1048 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {
     1123template< typename core_t >
     1124const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) {
    10491125        VISIT_START( node );
    10501126
     
    10611137//--------------------------------------------------------------------------
    10621138// LabelAddressExpr
    1063 template< typename pass_t >
    1064 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {
     1139template< typename core_t >
     1140const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) {
    10651141        VISIT_START( node );
    10661142
     
    10751151//--------------------------------------------------------------------------
    10761152// UntypedMemberExpr
    1077 template< typename pass_t >
    1078 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {
     1153template< typename core_t >
     1154const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) {
    10791155        VISIT_START( node );
    10801156
     
    10921168//--------------------------------------------------------------------------
    10931169// MemberExpr
    1094 template< typename pass_t >
    1095 const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {
     1170template< typename core_t >
     1171const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) {
    10961172        VISIT_START( node );
    10971173
     
    11081184//--------------------------------------------------------------------------
    11091185// VariableExpr
    1110 template< typename pass_t >
    1111 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {
     1186template< typename core_t >
     1187const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) {
    11121188        VISIT_START( node );
    11131189
     
    11221198//--------------------------------------------------------------------------
    11231199// ConstantExpr
    1124 template< typename pass_t >
    1125 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {
     1200template< typename core_t >
     1201const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) {
    11261202        VISIT_START( node );
    11271203
     
    11361212//--------------------------------------------------------------------------
    11371213// SizeofExpr
    1138 template< typename pass_t >
    1139 const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {
     1214template< typename core_t >
     1215const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) {
    11401216        VISIT_START( node );
    11411217
     
    11561232//--------------------------------------------------------------------------
    11571233// AlignofExpr
    1158 template< typename pass_t >
    1159 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {
     1234template< typename core_t >
     1235const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) {
    11601236        VISIT_START( node );
    11611237
     
    11761252//--------------------------------------------------------------------------
    11771253// UntypedOffsetofExpr
    1178 template< typename pass_t >
    1179 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {
     1254template< typename core_t >
     1255const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) {
    11801256        VISIT_START( node );
    11811257
     
    11921268//--------------------------------------------------------------------------
    11931269// OffsetofExpr
    1194 template< typename pass_t >
    1195 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {
     1270template< typename core_t >
     1271const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) {
    11961272        VISIT_START( node );
    11971273
     
    12081284//--------------------------------------------------------------------------
    12091285// OffsetPackExpr
    1210 template< typename pass_t >
    1211 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {
     1286template< typename core_t >
     1287const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) {
    12121288        VISIT_START( node );
    12131289
     
    12241300//--------------------------------------------------------------------------
    12251301// LogicalExpr
    1226 template< typename pass_t >
    1227 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {
     1302template< typename core_t >
     1303const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) {
    12281304        VISIT_START( node );
    12291305
     
    12411317//--------------------------------------------------------------------------
    12421318// ConditionalExpr
    1243 template< typename pass_t >
    1244 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {
     1319template< typename core_t >
     1320const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) {
    12451321        VISIT_START( node );
    12461322
     
    12591335//--------------------------------------------------------------------------
    12601336// CommaExpr
    1261 template< typename pass_t >
    1262 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {
     1337template< typename core_t >
     1338const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) {
    12631339        VISIT_START( node );
    12641340
     
    12761352//--------------------------------------------------------------------------
    12771353// TypeExpr
    1278 template< typename pass_t >
    1279 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {
     1354template< typename core_t >
     1355const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) {
    12801356        VISIT_START( node );
    12811357
     
    12921368//--------------------------------------------------------------------------
    12931369// AsmExpr
    1294 template< typename pass_t >
    1295 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {
     1370template< typename core_t >
     1371const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) {
    12961372        VISIT_START( node );
    12971373
     
    13091385//--------------------------------------------------------------------------
    13101386// ImplicitCopyCtorExpr
    1311 template< typename pass_t >
    1312 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
     1387template< typename core_t >
     1388const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
    13131389        VISIT_START( node );
    13141390
     
    13251401//--------------------------------------------------------------------------
    13261402// ConstructorExpr
    1327 template< typename pass_t >
    1328 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {
     1403template< typename core_t >
     1404const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) {
    13291405        VISIT_START( node );
    13301406
     
    13411417//--------------------------------------------------------------------------
    13421418// CompoundLiteralExpr
    1343 template< typename pass_t >
    1344 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {
     1419template< typename core_t >
     1420const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) {
    13451421        VISIT_START( node );
    13461422
     
    13571433//--------------------------------------------------------------------------
    13581434// RangeExpr
    1359 template< typename pass_t >
    1360 const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {
     1435template< typename core_t >
     1436const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) {
    13611437        VISIT_START( node );
    13621438
     
    13741450//--------------------------------------------------------------------------
    13751451// UntypedTupleExpr
    1376 template< typename pass_t >
    1377 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {
     1452template< typename core_t >
     1453const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) {
    13781454        VISIT_START( node );
    13791455
     
    13901466//--------------------------------------------------------------------------
    13911467// TupleExpr
    1392 template< typename pass_t >
    1393 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {
     1468template< typename core_t >
     1469const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) {
    13941470        VISIT_START( node );
    13951471
     
    14061482//--------------------------------------------------------------------------
    14071483// TupleIndexExpr
    1408 template< typename pass_t >
    1409 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {
     1484template< typename core_t >
     1485const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) {
    14101486        VISIT_START( node );
    14111487
     
    14221498//--------------------------------------------------------------------------
    14231499// TupleAssignExpr
    1424 template< typename pass_t >
    1425 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {
     1500template< typename core_t >
     1501const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) {
    14261502        VISIT_START( node );
    14271503
     
    14381514//--------------------------------------------------------------------------
    14391515// StmtExpr
    1440 template< typename pass_t >
    1441 const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {
     1516template< typename core_t >
     1517const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) {
    14421518        VISIT_START( node );
    14431519
    14441520        VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
    14451521                // get the stmts that will need to be spliced in
    1446                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    1447                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     1522                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     1523                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
    14481524
    14491525                // These may be modified by subnode but most be restored once we exit this statemnet.
    1450                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );
     1526                ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::typeSubs( core, 0 ) );
    14511527                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    14521528                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    14661542//--------------------------------------------------------------------------
    14671543// UniqueExpr
    1468 template< typename pass_t >
    1469 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {
     1544template< typename core_t >
     1545const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) {
    14701546        VISIT_START( node );
    14711547
     
    14821558//--------------------------------------------------------------------------
    14831559// UntypedInitExpr
    1484 template< typename pass_t >
    1485 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {
     1560template< typename core_t >
     1561const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) {
    14861562        VISIT_START( node );
    14871563
     
    14991575//--------------------------------------------------------------------------
    15001576// InitExpr
    1501 template< typename pass_t >
    1502 const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {
     1577template< typename core_t >
     1578const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) {
    15031579        VISIT_START( node );
    15041580
     
    15161592//--------------------------------------------------------------------------
    15171593// DeletedExpr
    1518 template< typename pass_t >
    1519 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {
     1594template< typename core_t >
     1595const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) {
    15201596        VISIT_START( node );
    15211597
     
    15331609//--------------------------------------------------------------------------
    15341610// DefaultArgExpr
    1535 template< typename pass_t >
    1536 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {
     1611template< typename core_t >
     1612const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) {
    15371613        VISIT_START( node );
    15381614
     
    15491625//--------------------------------------------------------------------------
    15501626// GenericExpr
    1551 template< typename pass_t >
    1552 const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {
     1627template< typename core_t >
     1628const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) {
    15531629        VISIT_START( node );
    15541630
     
    15781654
    15791655                if(mutated) {
    1580                         auto n = mutate(node);
     1656                        auto n = __pass::mutate<core_t>(node);
    15811657                        n->associations = std::move( new_kids );
    15821658                        node = n;
     
    15891665//--------------------------------------------------------------------------
    15901666// VoidType
    1591 template< typename pass_t >
    1592 const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {
     1667template< typename core_t >
     1668const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) {
    15931669        VISIT_START( node );
    15941670
     
    15981674//--------------------------------------------------------------------------
    15991675// BasicType
    1600 template< typename pass_t >
    1601 const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {
     1676template< typename core_t >
     1677const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) {
    16021678        VISIT_START( node );
    16031679
     
    16071683//--------------------------------------------------------------------------
    16081684// PointerType
    1609 template< typename pass_t >
    1610 const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {
     1685template< typename core_t >
     1686const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) {
    16111687        VISIT_START( node );
    16121688
     
    16211697//--------------------------------------------------------------------------
    16221698// ArrayType
    1623 template< typename pass_t >
    1624 const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {
     1699template< typename core_t >
     1700const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) {
    16251701        VISIT_START( node );
    16261702
     
    16351711//--------------------------------------------------------------------------
    16361712// ReferenceType
    1637 template< typename pass_t >
    1638 const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {
     1713template< typename core_t >
     1714const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) {
    16391715        VISIT_START( node );
    16401716
     
    16481724//--------------------------------------------------------------------------
    16491725// QualifiedType
    1650 template< typename pass_t >
    1651 const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {
     1726template< typename core_t >
     1727const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) {
    16521728        VISIT_START( node );
    16531729
     
    16621738//--------------------------------------------------------------------------
    16631739// FunctionType
    1664 template< typename pass_t >
    1665 const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) {
    1666         VISIT_START( node );
    1667 
    1668         VISIT(
    1669                 maybe_accept( node, &FunctionType::forall  );
     1740template< typename core_t >
     1741const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) {
     1742        VISIT_START( node );
     1743
     1744        VISIT({
     1745                // guard_forall_subs forall_guard { *this, node };
     1746                // mutate_forall( node );
     1747                maybe_accept( node, &FunctionType::assertions );
    16701748                maybe_accept( node, &FunctionType::returns );
    16711749                maybe_accept( node, &FunctionType::params  );
    1672         )
     1750        })
    16731751
    16741752        VISIT_END( Type, node );
     
    16771755//--------------------------------------------------------------------------
    16781756// StructInstType
    1679 template< typename pass_t >
    1680 const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {
    1681         VISIT_START( node );
    1682 
    1683         __pass::symtab::addStruct( pass, 0, node->name );
     1757template< typename core_t >
     1758const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) {
     1759        VISIT_START( node );
     1760
     1761        __pass::symtab::addStruct( core, 0, node->name );
    16841762
    16851763        VISIT({
    16861764                guard_symtab guard { *this };
    1687                 maybe_accept( node, &StructInstType::forall );
    16881765                maybe_accept( node, &StructInstType::params );
    16891766        })
     
    16941771//--------------------------------------------------------------------------
    16951772// UnionInstType
    1696 template< typename pass_t >
    1697 const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {
    1698         VISIT_START( node );
    1699 
    1700         __pass::symtab::addStruct( pass, 0, node->name );
    1701 
    1702         {
     1773template< typename core_t >
     1774const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) {
     1775        VISIT_START( node );
     1776
     1777        __pass::symtab::addUnion( core, 0, node->name );
     1778
     1779        VISIT({
    17031780                guard_symtab guard { *this };
    1704                 maybe_accept( node, &UnionInstType::forall );
    17051781                maybe_accept( node, &UnionInstType::params );
    1706         }
     1782        })
    17071783
    17081784        VISIT_END( Type, node );
     
    17111787//--------------------------------------------------------------------------
    17121788// EnumInstType
    1713 template< typename pass_t >
    1714 const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) {
    1715         VISIT_START( node );
    1716 
    1717         VISIT(
    1718                 maybe_accept( node, &EnumInstType::forall );
     1789template< typename core_t >
     1790const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) {
     1791        VISIT_START( node );
     1792
     1793        VISIT({
    17191794                maybe_accept( node, &EnumInstType::params );
    1720         )
     1795        })
    17211796
    17221797        VISIT_END( Type, node );
     
    17251800//--------------------------------------------------------------------------
    17261801// TraitInstType
    1727 template< typename pass_t >
    1728 const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) {
    1729         VISIT_START( node );
    1730 
    1731         VISIT(
    1732                 maybe_accept( node, &TraitInstType::forall );
     1802template< typename core_t >
     1803const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) {
     1804        VISIT_START( node );
     1805
     1806        VISIT({
    17331807                maybe_accept( node, &TraitInstType::params );
    1734         )
     1808        })
    17351809
    17361810        VISIT_END( Type, node );
     
    17391813//--------------------------------------------------------------------------
    17401814// TypeInstType
    1741 template< typename pass_t >
    1742 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) {
    1743         VISIT_START( node );
    1744 
    1745         VISIT(
    1746                 maybe_accept( node, &TypeInstType::forall );
    1747                 maybe_accept( node, &TypeInstType::params );
     1815template< typename core_t >
     1816const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) {
     1817        VISIT_START( node );
     1818
     1819        VISIT(
     1820                {
     1821                        maybe_accept( node, &TypeInstType::params );
     1822                }
     1823                // ensure that base re-bound if doing substitution
     1824                __pass::forall::replace( core, 0, node );
    17481825        )
    17491826
     
    17531830//--------------------------------------------------------------------------
    17541831// TupleType
    1755 template< typename pass_t >
    1756 const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {
     1832template< typename core_t >
     1833const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) {
    17571834        VISIT_START( node );
    17581835
     
    17671844//--------------------------------------------------------------------------
    17681845// TypeofType
    1769 template< typename pass_t >
    1770 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {
     1846template< typename core_t >
     1847const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) {
    17711848        VISIT_START( node );
    17721849
     
    17801857//--------------------------------------------------------------------------
    17811858// VarArgsType
    1782 template< typename pass_t >
    1783 const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {
     1859template< typename core_t >
     1860const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) {
    17841861        VISIT_START( node );
    17851862
     
    17891866//--------------------------------------------------------------------------
    17901867// ZeroType
    1791 template< typename pass_t >
    1792 const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {
     1868template< typename core_t >
     1869const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) {
    17931870        VISIT_START( node );
    17941871
     
    17981875//--------------------------------------------------------------------------
    17991876// OneType
    1800 template< typename pass_t >
    1801 const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {
     1877template< typename core_t >
     1878const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) {
    18021879        VISIT_START( node );
    18031880
     
    18071884//--------------------------------------------------------------------------
    18081885// GlobalScopeType
    1809 template< typename pass_t >
    1810 const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {
     1886template< typename core_t >
     1887const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) {
    18111888        VISIT_START( node );
    18121889
     
    18171894//--------------------------------------------------------------------------
    18181895// Designation
    1819 template< typename pass_t >
    1820 const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {
     1896template< typename core_t >
     1897const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) {
    18211898        VISIT_START( node );
    18221899
     
    18281905//--------------------------------------------------------------------------
    18291906// SingleInit
    1830 template< typename pass_t >
    1831 const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
     1907template< typename core_t >
     1908const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) {
    18321909        VISIT_START( node );
    18331910
     
    18411918//--------------------------------------------------------------------------
    18421919// ListInit
    1843 template< typename pass_t >
    1844 const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
     1920template< typename core_t >
     1921const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) {
    18451922        VISIT_START( node );
    18461923
     
    18551932//--------------------------------------------------------------------------
    18561933// ConstructorInit
    1857 template< typename pass_t >
    1858 const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
     1934template< typename core_t >
     1935const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) {
    18591936        VISIT_START( node );
    18601937
     
    18701947//--------------------------------------------------------------------------
    18711948// Attribute
    1872 template< typename pass_t >
    1873 const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
     1949template< typename core_t >
     1950const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node  )  {
    18741951        VISIT_START( node );
    18751952
     
    18831960//--------------------------------------------------------------------------
    18841961// TypeSubstitution
    1885 template< typename pass_t >
    1886 const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
     1962template< typename core_t >
     1963const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) {
    18871964        VISIT_START( node );
    18881965
     
    18901967                {
    18911968                        bool mutated = false;
    1892                         std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
     1969                        std::unordered_map< ast::TypeInstType::TypeEnvKey, ast::ptr< ast::Type > > new_map;
    18931970                        for ( const auto & p : node->typeEnv ) {
    18941971                                guard_symtab guard { *this };
    18951972                                auto new_node = p.second->accept( *this );
    1896                                 if (new_node != p.second) mutated = false;
     1973                                if (new_node != p.second) mutated = true;
    18971974                                new_map.insert({ p.first, new_node });
    18981975                        }
    18991976                        if (mutated) {
    1900                                 auto new_node = mutate( node );
     1977                                auto new_node = __pass::mutate<core_t>( node );
    19011978                                new_node->typeEnv.swap( new_map );
    19021979                                node = new_node;
    19031980                        }
    19041981                }
    1905 
    1906                 {
    1907                         bool mutated = false;
    1908                         std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
    1909                         for ( const auto & p : node->varEnv ) {
    1910                                 guard_symtab guard { *this };
    1911                                 auto new_node = p.second->accept( *this );
    1912                                 if (new_node != p.second) mutated = false;
    1913                                 new_map.insert({ p.first, new_node });
    1914                         }
    1915                         if (mutated) {
    1916                                 auto new_node = mutate( node );
    1917                                 new_node->varEnv.swap( new_map );
    1918                                 node = new_node;
    1919                         }
    1920                 }
    19211982        )
    19221983
  • src/AST/Pass.proto.hpp

    r3c64c668 r58fe85a  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
     19#include "Common/Stats/Heap.h"
     20
    1921namespace ast {
    20 template<typename pass_type>
     22template<typename core_t>
    2123class Pass;
     24
     25struct TranslationUnit;
     26
     27struct PureVisitor;
    2228
    2329namespace __pass {
     
    8288                };
    8389
    84                 std::stack< cleanup_t > cleanups;
     90                std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
    8591        };
    8692
     
    111117        /// "Short hand" to check if this is a valid previsit function
    112118        /// Mostly used to make the static_assert look (and print) prettier
    113         template<typename pass_t, typename node_t>
     119        template<typename core_t, typename node_t>
    114120        struct is_valid_previsit {
    115                 using ret_t = decltype( ((pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );
     121                using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) );
    116122
    117123                static constexpr bool value = std::is_void< ret_t >::value ||
     
    127133        template<>
    128134        struct __assign<true> {
    129                 template<typename pass_t, typename node_t>
    130                 static inline void result( pass_t & pass, const node_t * & node ) {
    131                         pass.previsit( node );
     135                template<typename core_t, typename node_t>
     136                static inline void result( core_t & core, const node_t * & node ) {
     137                        core.previsit( node );
    132138                }
    133139        };
     
    135141        template<>
    136142        struct __assign<false> {
    137                 template<typename pass_t, typename node_t>
    138                 static inline void result( pass_t & pass, const node_t * & node ) {
    139                         node = pass.previsit( node );
     143                template<typename core_t, typename node_t>
     144                static inline void result( core_t & core, const node_t * & node ) {
     145                        node = core.previsit( node );
    140146                        assertf(node, "Previsit must not return NULL");
    141147                }
     
    150156        template<>
    151157        struct __return<true> {
    152                 template<typename pass_t, typename node_t>
    153                 static inline const node_t * result( pass_t & pass, const node_t * & node ) {
    154                         pass.postvisit( node );
     158                template<typename core_t, typename node_t>
     159                static inline const node_t * result( core_t & core, const node_t * & node ) {
     160                        core.postvisit( node );
    155161                        return node;
    156162                }
     
    159165        template<>
    160166        struct __return<false> {
    161                 template<typename pass_t, typename node_t>
    162                 static inline auto result( pass_t & pass, const node_t * & node ) {
    163                         return pass.postvisit( node );
     167                template<typename core_t, typename node_t>
     168                static inline auto result( core_t & core, const node_t * & node ) {
     169                        return core.postvisit( node );
    164170                }
    165171        };
     
    180186        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    181187        // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    182         template<typename pass_t, typename node_t>
    183         static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
     188        template<typename core_t, typename node_t>
     189        static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
    184190                static_assert(
    185                         is_valid_previsit<pass_t, node_t>::value,
     191                        is_valid_previsit<core_t, node_t>::value,
    186192                        "Previsit may not change the type of the node. It must return its paremeter or void."
    187193                );
     
    189195                __assign<
    190196                        std::is_void<
    191                                 decltype( pass.previsit( node ) )
     197                                decltype( core.previsit( node ) )
    192198                        >::value
    193                 >::result( pass, node );
    194         }
    195 
    196         template<typename pass_t, typename node_t>
    197         static inline auto previsit( pass_t &, const node_t *, long ) {}
     199                >::result( core, node );
     200        }
     201
     202        template<typename core_t, typename node_t>
     203        static inline auto previsit( core_t &, const node_t *, long ) {}
    198204
    199205        // PostVisit : never mutates the passed pointer but may return a different node
    200         template<typename pass_t, typename node_t>
    201         static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->
    202                 decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
     206        template<typename core_t, typename node_t>
     207        static inline auto postvisit( core_t & core, const node_t * node, int ) ->
     208                decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    203209        {
    204210                return __return<
    205211                        std::is_void<
    206                                 decltype( pass.postvisit( node ) )
     212                                decltype( core.postvisit( node ) )
    207213                        >::value
    208                 >::result( pass, node );
    209         }
    210 
    211         template<typename pass_t, typename node_t>
    212         static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
     214                >::result( core, node );
     215        }
     216
     217        template<typename core_t, typename node_t>
     218        static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
    213219
    214220        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    225231        // The type is not strictly enforced but does match the accessory
    226232        #define FIELD_PTR( name, default_type ) \
    227         template< typename pass_t > \
    228         static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
     233        template< typename core_t > \
     234        static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
    229235        \
    230         template< typename pass_t > \
    231         static inline default_type * name( pass_t &, long ) { return nullptr; }
     236        template< typename core_t > \
     237        static inline default_type * name( core_t &, long ) { return nullptr; }
    232238
    233239        // List of fields and their expected types
    234         FIELD_PTR( env, const ast::TypeSubstitution * )
     240        FIELD_PTR( typeSubs, const ast::TypeSubstitution * )
    235241        FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
    236242        FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
     
    239245        FIELD_PTR( visit_children, __pass::bool_ref )
    240246        FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    241         FIELD_PTR( visitor, ast::Pass<pass_t> * const )
     247        FIELD_PTR( visitor, ast::Pass<core_t> * const )
    242248
    243249        // Remove the macro to make sure we don't clash
    244250        #undef FIELD_PTR
     251
     252        template< typename core_t >
     253        static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     254                // Stats::Heap::stacktrace_push(core_t::traceId);
     255        }
     256
     257        template< typename core_t >
     258        static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     259                // Stats::Heap::stacktrace_pop();
     260        }
     261
     262        template< typename core_t >
     263        static void beginTrace(core_t &, long) {}
     264
     265        template< typename core_t >
     266        static void endTrace(core_t &, long) {}
     267
     268        // Allows visitor to handle an error on top-level declarations, and possibly suppress the error.
     269        // If onError() returns false, the error will be ignored. By default, it returns true.
     270
     271        template< typename core_t >
     272        static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
     273
     274        template< typename core_t >
     275        static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
     276                return core.on_error(decl);
     277        }
    245278
    246279        // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     
    248281        // detect it using the same strategy
    249282        namespace scope {
    250                 template<typename pass_t>
    251                 static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
    252                         pass.beginScope();
    253                 }
    254 
    255                 template<typename pass_t>
    256                 static inline void enter( pass_t &, long ) {}
    257 
    258                 template<typename pass_t>
    259                 static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
    260                         pass.endScope();
    261                 }
    262 
    263                 template<typename pass_t>
    264                 static inline void leave( pass_t &, long ) {}
    265         };
    266 
    267         // Finally certain pass desire an up to date symbol table automatically
     283                template<typename core_t>
     284                static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
     285                        core.beginScope();
     286                }
     287
     288                template<typename core_t>
     289                static inline void enter( core_t &, long ) {}
     290
     291                template<typename core_t>
     292                static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
     293                        core.endScope();
     294                }
     295
     296                template<typename core_t>
     297                static inline void leave( core_t &, long ) {}
     298        } // namespace scope
     299
     300        // Certain passes desire an up to date symbol table automatically
    268301        // detect the presence of a member name `symtab` and call all the members appropriately
    269302        namespace symtab {
    270303                // Some simple scoping rules
    271                 template<typename pass_t>
    272                 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {
    273                         pass.symtab.enterScope();
    274                 }
    275 
    276                 template<typename pass_t>
    277                 static inline auto enter( pass_t &, long ) {}
    278 
    279                 template<typename pass_t>
    280                 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {
    281                         pass.symtab.leaveScope();
    282                 }
    283 
    284                 template<typename pass_t>
    285                 static inline auto leave( pass_t &, long ) {}
     304                template<typename core_t>
     305                static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
     306                        core.symtab.enterScope();
     307                }
     308
     309                template<typename core_t>
     310                static inline auto enter( core_t &, long ) {}
     311
     312                template<typename core_t>
     313                static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
     314                        core.symtab.leaveScope();
     315                }
     316
     317                template<typename core_t>
     318                static inline auto leave( core_t &, long ) {}
    286319
    287320                // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
    288321                // Create macro to condense these common patterns
    289322                #define SYMTAB_FUNC1( func, type ) \
    290                 template<typename pass_t> \
    291                 static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.symtab.func( arg ), void() ) {\
    292                         pass.symtab.func( arg ); \
     323                template<typename core_t> \
     324                static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
     325                        core.symtab.func( arg ); \
    293326                } \
    294327                \
    295                 template<typename pass_t> \
    296                 static inline void func( pass_t &, long, type ) {}
     328                template<typename core_t> \
     329                static inline void func( core_t &, long, type ) {}
    297330
    298331                #define SYMTAB_FUNC2( func, type1, type2 ) \
    299                 template<typename pass_t> \
    300                 static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.symtab.func( arg1, arg2 ), void () ) {\
    301                         pass.symtab.func( arg1, arg2 ); \
     332                template<typename core_t> \
     333                static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
     334                        core.symtab.func( arg1, arg2 ); \
    302335                } \
    303336                        \
    304                 template<typename pass_t> \
    305                 static inline void func( pass_t &, long, type1, type2 ) {}
     337                template<typename core_t> \
     338                static inline void func( core_t &, long, type1, type2 ) {}
    306339
    307340                SYMTAB_FUNC1( addId     , const DeclWithType *  );
     
    311344                SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
    312345                SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
    313                 SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
     346                SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
    314347
    315348                // A few extra functions have more complicated behaviour, they are hand written
    316                 template<typename pass_t>
    317                 static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {
     349                template<typename core_t>
     350                static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
    318351                        ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    319352                        fwd->params = decl->params;
    320                         pass.symtab.addStruct( fwd );
    321                 }
    322 
    323                 template<typename pass_t>
    324                 static inline void addStructFwd( pass_t &, long, const ast::StructDecl * ) {}
    325 
    326                 template<typename pass_t>
    327                 static inline auto addUnionFwd( pass_t & pass, int, const ast::UnionDecl * decl ) -> decltype( pass.symtab.addUnion( decl ), void() ) {
     353                        core.symtab.addStruct( fwd );
     354                }
     355
     356                template<typename core_t>
     357                static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
     358
     359                template<typename core_t>
     360                static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
    328361                        UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
    329362                        fwd->params = decl->params;
    330                         pass.symtab.addUnion( fwd );
    331                 }
    332 
    333                 template<typename pass_t>
    334                 static inline void addUnionFwd( pass_t &, long, const ast::UnionDecl * ) {}
    335 
    336                 template<typename pass_t>
    337                 static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addStruct( str ), void() ) {
    338                         if ( ! pass.symtab.lookupStruct( str ) ) {
    339                                 pass.symtab.addStruct( str );
     363                        core.symtab.addUnion( fwd );
     364                }
     365
     366                template<typename core_t>
     367                static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
     368
     369                template<typename core_t>
     370                static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
     371                        if ( ! core.symtab.lookupStruct( str ) ) {
     372                                core.symtab.addStruct( str );
    340373                        }
    341374                }
    342375
    343                 template<typename pass_t>
    344                 static inline void addStruct( pass_t &, long, const std::string & ) {}
    345 
    346                 template<typename pass_t>
    347                 static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addUnion( str ), void() ) {
    348                         if ( ! pass.symtab.lookupUnion( str ) ) {
    349                                 pass.symtab.addUnion( str );
     376                template<typename core_t>
     377                static inline void addStruct( core_t &, long, const std::string & ) {}
     378
     379                template<typename core_t>
     380                static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
     381                        if ( ! core.symtab.lookupUnion( str ) ) {
     382                                core.symtab.addUnion( str );
    350383                        }
    351384                }
    352385
    353                 template<typename pass_t>
    354                 static inline void addUnion( pass_t &, long, const std::string & ) {}
     386                template<typename core_t>
     387                static inline void addUnion( core_t &, long, const std::string & ) {}
    355388
    356389                #undef SYMTAB_FUNC1
    357390                #undef SYMTAB_FUNC2
    358         };
    359 };
    360 };
     391        } // namespace symtab
     392
     393        // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
     394        // Detect the presence of a member name `subs` and call all members appropriately
     395        namespace forall {
     396                // Some simple scoping rules
     397                template<typename core_t>
     398                static inline auto enter( core_t & core, int, const ast::FunctionType * type )
     399                -> decltype( core.subs, void() ) {
     400                        if ( ! type->forall.empty() ) core.subs.beginScope();
     401                }
     402
     403                template<typename core_t>
     404                static inline auto enter( core_t &, long, const ast::FunctionType * ) {}
     405
     406                template<typename core_t>
     407                static inline auto leave( core_t & core, int, const ast::FunctionType * type )
     408                -> decltype( core.subs, void() ) {
     409                        if ( ! type->forall.empty() ) { core.subs.endScope(); }
     410                }
     411
     412                template<typename core_t>
     413                static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
     414
     415                // Replaces a TypeInstType's base TypeDecl according to the table
     416                template<typename core_t>
     417                static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
     418                -> decltype( core.subs, void() ) {
     419                        inst = ast::mutate_field(
     420                                inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
     421                }
     422
     423                template<typename core_t>
     424                static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
     425
     426        } // namespace forall
     427
     428        template<typename core_t>
     429        static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) {
     430                return core.result();
     431        }
     432
     433        template<typename core_t>
     434        static inline auto get_result( core_t & core, int ) -> decltype( core.result ) {
     435                return core.result;
     436        }
     437
     438        template<typename core_t>
     439        static inline void get_result( core_t &, long ) {}
     440} // namespace __pass
     441} // namespace ast
  • src/AST/Print.cpp

    r3c64c668 r58fe85a  
    2121#include "Type.hpp"
    2222#include "TypeSubstitution.hpp"
     23#include "CompilationState.h"
    2324
    2425#include "Common/utility.h" // for group_iterate
     
    2930
    3031template <typename C, typename... T>
    31 constexpr auto make_array(T&&... values) ->
    32         array<C,sizeof...(T)>
     32constexpr array<C,sizeof...(T)> make_array(T&&... values)
    3333{
    3434        return array<C,sizeof...(T)>{
     
    129129
    130130        void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
    131                 switch ( inferred.mode ) {
    132                 case ast::Expr::InferUnion::Empty: return;
    133                 case ast::Expr::InferUnion::Slots: {
    134                         os << indent << "with " << inferred.data.resnSlots.size()
     131                if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) {
     132                        os << indent << "with " << inferred.data.resnSlots->size()
    135133                           << " pending inference slots" << endl;
    136                         return;
    137                 }
    138                 case ast::Expr::InferUnion::Params: {
     134                }
     135                if (inferred.data.inferParams && !inferred.data.inferParams->empty()) {
    139136                        os << indent << "with inferred parameters " << level << ":" << endl;
    140137                        ++indent;
    141                         for ( const auto & i : inferred.data.inferParams ) {
     138                        for ( const auto & i : *inferred.data.inferParams ) {
    142139                                os << indent;
    143                                 short_print( Decl::fromId( i.second.decl ) );
     140                                short_print( i.second.declptr );
    144141                                os << endl;
    145142                                print( i.second.expr->inferred, level+1 );
    146143                        }
    147144                        --indent;
    148                         return;
    149                 }
    150                 }
    151         }
    152 
    153         void print( const ast::ParameterizedType::ForallList & forall ) {
     145                }
     146        }
     147
     148        void print( const ast::FunctionType::ForallList & forall ) {
    154149                if ( forall.empty() ) return;
    155150                os << "forall" << endl;
    156151                ++indent;
    157152                printAll( forall );
     153                os << indent;
     154                --indent;
     155        }
     156
     157        void print( const ast::FunctionType::AssertionList & assts ) {
     158                if (assts.empty()) return;
     159                os << "with assertions" << endl;
     160                ++indent;
     161                printAll(assts);
    158162                os << indent;
    159163                --indent;
     
    210214
    211215        void preprint( const ast::NamedTypeDecl * node ) {
    212                 if ( ! node->name.empty() ) os << node->name << ": ";
     216                if ( ! node->name.empty() ) {
     217                        os << node->name << ": ";
     218                }
    213219
    214220                if ( ! short_mode && node->linkage != Linkage::Cforall ) {
     
    226232                }
    227233
    228                 if ( ! node->params.empty() ) {
    229                         os << endl << indent << "... with parameters" << endl;
    230                         ++indent;
    231                         printAll( node->params );
    232                         --indent;
    233                 }
    234 
    235                 if ( ! short_mode && ! node->assertions.empty() ) {
     234                if ( ! node->assertions.empty() ) {
    236235                        os << endl << indent << "... with assertions" << endl;
    237236                        ++indent;
     
    244243                print( node->inferred );
    245244
     245                if ( node->result ) {
     246                        os << endl << indent << "... with resolved type:" << endl;
     247                        ++indent;
     248                        os << indent;
     249                        node->result->accept( *this );
     250                        --indent;
     251                }
     252
    246253                if ( node->env ) {
    247254                        os << endl << indent << "... with environment:" << endl;
     
    260267        }
    261268
    262         void preprint( const ast::ParameterizedType * node ) {
     269        void preprint( const ast::FunctionType * node ) {
    263270                print( node->forall );
     271                print( node->assertions );
    264272                print( node->qualifiers );
    265273        }
    266274
    267         void preprint( const ast::ReferenceToType * node ) {
    268                 print( node->forall );
     275        void preprint( const ast::BaseInstType * node ) {
    269276                print( node->attributes );
    270277                print( node->qualifiers );
     
    678685        }
    679686
     687        virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
     688                os << "Suspend Statement";
     689                switch (node->type) {
     690                        case ast::SuspendStmt::None     : os << " with implicit target"; break;
     691                        case ast::SuspendStmt::Generator: os << " for generator"; break;
     692                        case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
     693                }
     694                os << endl;
     695
     696                ++indent;
     697                if(node->then) {
     698                        os << indent << " with post statement :" << endl;
     699                        safe_print( node->then );
     700                }
     701                ++indent;
     702
     703                return node;
     704        }
     705
    680706        virtual const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    681707                os << "Waitfor Statement" << endl;
     
    823849        virtual const ast::Expr * visit( const ast::CastExpr * node ) override final {
    824850                ++indent;
    825                 os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;
     851                os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent;
    826852                safe_print( node->arg );
    827853                os << endl << indent-1 << "... to:";
     
    13581384        virtual const ast::Type * visit( const ast::TypeInstType * node ) override final {
    13591385                preprint( node );
    1360                 os << "instance of type " << node->name
     1386                const auto & _name = deterministic_output && isUnboundType(node) ? "[unbound]" : node->typeString();
     1387                os << "instance of type " << _name
    13611388                   << " (" << (node->kind == ast::TypeDecl::Ftype ? "" : "not ") << "function type)";
    13621389                print( node->params );
     
    14841511                os << indent << "Types:" << endl;
    14851512                for ( const auto& i : *node ) {
    1486                         os << indent+1 << i.first << " -> ";
     1513                        os << indent+1 << i.first.typeString() << " -> ";
    14871514                        indent += 2;
    14881515                        safe_print( i.second );
    1489                         indent -= 2;
    1490                         os << endl;
    1491                 }
    1492                 os << indent << "Non-types:" << endl;
    1493                 for ( auto i = node->beginVar(); i != node->endVar(); ++i ) {
    1494                         os << indent+1 << i->first << " -> ";
    1495                         indent += 2;
    1496                         safe_print( i->second );
    14971516                        indent -= 2;
    14981517                        os << endl;
  • src/AST/Stmt.hpp

    r3c64c668 r58fe85a  
    2727
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    29 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     29#define MUTATE_FRIEND \
     30    template<typename node_t> friend node_t * mutate(const node_t * node); \
     31        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3032
    3133namespace ast {
     
    342344};
    343345
     346/// Suspend statement
     347class SuspendStmt final : public Stmt {
     348public:
     349        ptr<CompoundStmt> then;
     350        enum Type { None, Coroutine, Generator } type = None;
     351
     352        SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, std::vector<Label> && labels = {} )
     353        : Stmt(loc, std::move(labels)), then(then), type(type) {}
     354
     355        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     356private:
     357        SuspendStmt * clone() const override { return new SuspendStmt{ *this }; }
     358        MUTATE_FRIEND
     359};
     360
    344361/// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...`
    345362class WaitForStmt final : public Stmt {
     
    397414class ImplicitCtorDtorStmt final : public Stmt {
    398415public:
    399         readonly<Stmt> callStmt;
     416        ptr<Stmt> callStmt;
    400417
    401418        ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
  • src/AST/SymbolTable.cpp

    r3c64c668 r58fe85a  
    9595}
    9696
     97SymbolTable::SpecialFunctionKind SymbolTable::getSpecialFunctionKind(const std::string & name) {
     98        if (name == "?{}") return CTOR;
     99        if (name == "^?{}") return DTOR;
     100        if (name == "?=?") return ASSIGN;
     101        return NUMBER_OF_KINDS;
     102}
     103
    97104std::vector<SymbolTable::IdData> SymbolTable::lookupId( const std::string &id ) const {
     105        static Stats::Counters::CounterGroup * name_lookup_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Name Lookup Stats");
     106        static std::map<std::string, Stats::Counters::SimpleCounter *> lookups_by_name;
     107        static std::map<std::string, Stats::Counters::SimpleCounter *> candidates_by_name;
     108
     109        SpecialFunctionKind kind = getSpecialFunctionKind(id);
     110        if (kind != NUMBER_OF_KINDS) return specialLookupId(kind);
     111
    98112        ++*stats().lookup_calls;
    99113        if ( ! idTable ) return {};
     
    107121                out.push_back( decl.second );
    108122        }
     123
     124        if (Stats::Counters::enabled) {
     125                if (! lookups_by_name.count(id)) {
     126                        // leaks some strings, but it is because Counters do not hold them
     127                        auto lookupCounterName = new std::string(id + "%count");
     128                        auto candidatesCounterName = new std::string(id + "%candidate");
     129                        lookups_by_name.emplace(id, new Stats::Counters::SimpleCounter(lookupCounterName->c_str(), name_lookup_stats));
     130                        candidates_by_name.emplace(id, new Stats::Counters::SimpleCounter(candidatesCounterName->c_str(), name_lookup_stats));
     131                }
     132                (*lookups_by_name[id]) ++;
     133                *candidates_by_name[id] += out.size();
     134        }
     135
     136        return out;
     137}
     138
     139std::vector<SymbolTable::IdData> SymbolTable::specialLookupId( SymbolTable::SpecialFunctionKind kind, const std::string & otypeKey ) const {
     140        static Stats::Counters::CounterGroup * special_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Special Lookups");
     141        static Stats::Counters::SimpleCounter * stat_counts[3] = {
     142                Stats::Counters::build<Stats::Counters::SimpleCounter>("constructor - count", special_stats),
     143                Stats::Counters::build<Stats::Counters::SimpleCounter>("destructor - count", special_stats),
     144                Stats::Counters::build<Stats::Counters::SimpleCounter>("assignment - count", special_stats)
     145        };
     146
     147        static Stats::Counters::SimpleCounter * stat_candidates[3] = {
     148                Stats::Counters::build<Stats::Counters::SimpleCounter>("constructor - candidates", special_stats),
     149                Stats::Counters::build<Stats::Counters::SimpleCounter>("destructor - candidates", special_stats),
     150                Stats::Counters::build<Stats::Counters::SimpleCounter>("assignment - candidates", special_stats)
     151        };
     152
     153        static Stats::Counters::SimpleCounter * num_lookup_with_key
     154                = Stats::Counters::build<Stats::Counters::SimpleCounter>("keyed lookups", special_stats);
     155        static Stats::Counters::SimpleCounter * num_lookup_without_key
     156                = Stats::Counters::build<Stats::Counters::SimpleCounter>("unkeyed lookups", special_stats);
     157
     158        assert (kind != NUMBER_OF_KINDS);
     159        ++*stats().lookup_calls;
     160        if ( ! specialFunctionTable[kind] ) return {};
     161
     162        std::vector<IdData> out;
     163
     164        if (otypeKey.empty()) { // returns everything
     165                ++*num_lookup_without_key;
     166                for (auto & table : *specialFunctionTable[kind]) {
     167                        for (auto & decl : *table.second) {
     168                                out.push_back(decl.second);
     169                        }
     170                }
     171        }
     172        else {
     173                ++*num_lookup_with_key;
     174                ++*stats().map_lookups;
     175                auto decls = specialFunctionTable[kind]->find(otypeKey);
     176                if (decls == specialFunctionTable[kind]->end()) return {};
     177
     178                for (auto decl : *(decls->second)) {
     179                        out.push_back(decl.second);
     180                }
     181        }
     182
     183        ++*stat_counts[kind];
     184        *stat_candidates[kind] += out.size();
     185
    109186        return out;
    110187}
     
    313390                if ( ! expr->result ) continue;
    314391                const Type * resTy = expr->result->stripReferences();
    315                 auto aggrType = dynamic_cast< const ReferenceToType * >( resTy );
     392                auto aggrType = dynamic_cast< const BaseInstType * >( resTy );
    316393                assertf( aggrType, "WithStmt expr has non-aggregate type: %s",
    317394                        toString( expr->result ).c_str() );
     
    335412}
    336413
    337 void SymbolTable::addFunctionType( const FunctionType * ftype ) {
    338         addTypes( ftype->forall );
    339         addIds( ftype->returns );
    340         addIds( ftype->params );
    341 }
     414
     415void SymbolTable::addFunction( const FunctionDecl * func ) {
     416        for (auto & td : func->type_params) {
     417                addType(td);
     418        }
     419        for (auto & asst : func->assertions) {
     420                addId(asst);
     421        }
     422        // addTypes( func->type->forall );
     423        addIds( func->returns );
     424        addIds( func->params );
     425}
     426
    342427
    343428void SymbolTable::lazyInitScope() {
     
    364449namespace {
    365450        /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
    366         std::string getOtypeKey( const FunctionDecl * function ) {
    367                 const auto & params = function->type->params;
     451        std::string getOtypeKey( const FunctionType * ftype, bool stripParams = true ) {
     452                const auto & params = ftype->params;
    368453                assert( ! params.empty() );
    369454                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
    370                 const Type * base = InitTweak::getPointerBase( params.front()->get_type() );
     455                const Type * base = InitTweak::getPointerBase( params.front() );
    371456                assert( base );
    372                 return Mangle::mangle( base );
     457                if (stripParams) {
     458                        if (dynamic_cast<const PointerType *>(base)) return Mangle::Encoding::pointer;
     459                        return Mangle::mangle( base, Mangle::Type | Mangle::NoGenericParams );
     460                }
     461                else
     462                        return Mangle::mangle( base ); 
    373463        }
    374464
     
    378468                        const DeclWithType * decl, const std::string & otypeKey ) {
    379469                auto func = dynamic_cast< const FunctionDecl * >( decl );
    380                 if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
     470                if ( ! func || otypeKey != getOtypeKey( func->type, false ) ) return nullptr;
    381471                return func;
    382472        }
     
    403493        bool dataIsUserDefinedFunc = ! function->linkage.is_overrideable;
    404494        bool dataIsCopyFunc = InitTweak::isCopyFunction( function );
    405         std::string dataOtypeKey = getOtypeKey( function );
     495        std::string dataOtypeKey = getOtypeKey( function->type, false ); // requires exact match to override autogen
    406496
    407497        if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
     
    575665                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    576666                const Decl * deleter ) {
     667        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
     668        if (kind == NUMBER_OF_KINDS) { // not a special decl
     669                addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
     670        }
     671        else {
     672                std::string key;
     673                if (auto func = dynamic_cast<const FunctionDecl *>(decl)) {
     674                        key = getOtypeKey(func->type);
     675                }
     676                else if (auto obj = dynamic_cast<const ObjectDecl *>(decl)) {
     677                        key = getOtypeKey(obj->type.strict_as<PointerType>()->base.strict_as<FunctionType>());
     678                }
     679                else {
     680                        assertf(false, "special decl with non-function type");
     681                }
     682                addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
     683        }
     684}
     685
     686void SymbolTable::addId(
     687                const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
     688                const Decl * deleter ) {
    577689        ++*stats().add_calls;
    578690        const std::string &name = decl->name;
     
    605717        // ensure tables exist and add identifier
    606718        MangleTable::Ptr mangleTable;
    607         if ( ! idTable ) {
    608                 idTable = IdTable::new_ptr();
     719        if ( ! table ) {
     720                table = IdTable::new_ptr();
    609721                mangleTable = MangleTable::new_ptr();
    610722        } else {
    611723                ++*stats().map_lookups;
    612                 auto decls = idTable->find( name );
    613                 if ( decls == idTable->end() ) {
     724                auto decls = table->find( lookupKey );
     725                if ( decls == table->end() ) {
    614726                        mangleTable = MangleTable::new_ptr();
    615727                } else {
     
    626738                                                lazyInitScope();
    627739                                                *stats().map_mutations += 2;
    628                                                 idTable = idTable->set(
    629                                                         name,
     740                                                table = table->set(
     741                                                        lookupKey,
    630742                                                        mangleTable->set(
    631743                                                                mangleName,
     
    642754        IdData data{ decl, baseExpr, deleter, scope };
    643755        // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary
    644         if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
     756        if (table != idTable) { // adding to special table
     757                if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
     758        }
    645759        *stats().map_mutations += 2;
    646         idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
     760        table = table->set( lookupKey, mangleTable->set( mangleName, std::move(data) ) );
    647761}
    648762
     
    654768                        if ( dwt->name == "" ) {
    655769                                const Type * t = dwt->get_type()->stripReferences();
    656                                 if ( auto rty = dynamic_cast<const ReferenceToType *>( t ) ) {
     770                                if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
    657771                                        if ( ! dynamic_cast<const StructInstType *>(rty)
    658772                                                && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
  • src/AST/SymbolTable.hpp

    r3c64c668 r58fe85a  
    3333class SymbolTable final : public std::enable_shared_from_this<ast::SymbolTable> {
    3434public:
     35        /// special functions stored in dedicated tables, with different lookup keys
     36        enum SpecialFunctionKind {CTOR, DTOR, ASSIGN, NUMBER_OF_KINDS};
     37        static SpecialFunctionKind getSpecialFunctionKind(const std::string & name);
     38
    3539        /// Stored information about a declaration
    3640        struct IdData {
     
    7781        UnionTable::Ptr unionTable;    ///< union namespace
    7882        TraitTable::Ptr traitTable;    ///< trait namespace
     83        IdTable::Ptr specialFunctionTable[NUMBER_OF_KINDS];
     84
     85        // using SpecialFuncTable = PersistentMap< std::string, IdTable::Ptr >; // fname (ctor/dtor/assign) - otypekey
     86        // SpecialFuncTable::Ptr specialFuncTable;
    7987
    8088        using Ptr = std::shared_ptr<const SymbolTable>;
     
    95103        /// Gets all declarations with the given ID
    96104        std::vector<IdData> lookupId( const std::string &id ) const;
     105        /// Gets special functions associated with a type; if no key is given, returns everything
     106        std::vector<IdData> specialLookupId( SpecialFunctionKind kind, const std::string & otypeKey = "" ) const;
    97107        /// Gets the top-most type declaration with the given ID
    98108        const NamedTypeDecl * lookupType( const std::string &id ) const;
     
    145155
    146156        /// convenience function for adding all of the declarations in a function type to the indexer
    147         void addFunctionType( const FunctionType * ftype );
     157        void addFunction( const FunctionDecl * );
    148158
    149159private:
     
    186196                const Decl * deleter = nullptr );
    187197
     198        /// common code for addId when special decls are placed into separate tables
     199        void addId(
     200                const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & idTable, OnConflict handleConflicts,
     201                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr);
     202       
    188203        /// adds all of the members of the Aggregate (addWith helper)
    189204        void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts );
  • src/AST/Type.cpp

    r3c64c668 r58fe85a  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon May 13 15:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 15 16:56:28 2019
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jul 23 14:16:00 2020
     13// Update Count     : 5
    1414//
    1515
     
    2222#include "Decl.hpp"
    2323#include "Init.hpp"
     24#include "Common/utility.h"      // for copy, move
    2425#include "InitTweak/InitTweak.h" // for getPointerBase
    2526#include "Tuples/Tuples.h"       // for isTtype
     
    9192
    9293// --- FunctionType
    93 
    9494namespace {
    95         bool containsTtype( const std::vector<ptr<DeclWithType>> & l ) {
     95        bool containsTtype( const std::vector<ptr<Type>> & l ) {
    9696                if ( ! l.empty() ) {
    97                         return Tuples::isTtype( l.back()->get_type() );
     97                        return Tuples::isTtype( l.back() );
    9898                }
    9999                return false;
     
    105105}
    106106
    107 // --- ReferenceToType
    108 std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
     107std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const {
    109108        assertf( aggr(), "Must have aggregate to perform lookup" );
    110109
     
    116115}
    117116
    118 // --- StructInstType
     117// --- SueInstType (StructInstType, UnionInstType, EnumInstType)
    119118
    120 StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
    121         std::vector<ptr<Attribute>>&& as )
    122 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     119template<typename decl_t>
     120SueInstType<decl_t>::SueInstType(
     121        const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     122: BaseInstType( b->name, q, move(as) ), base( b ) {}
    123123
    124 bool StructInstType::isComplete() const { return base ? base->body : false; }
     124template<typename decl_t>
     125SueInstType<decl_t>::SueInstType(
     126        const base_type * b, std::vector<ptr<Expr>> && params,
     127        CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
     128: BaseInstType( b->name, std::move(params), q, std::move(as) ), base( b ) {}
    125129
    126 // --- UnionInstType
     130template<typename decl_t>
     131bool SueInstType<decl_t>::isComplete() const {
     132        return base ? base->body : false;
     133}
    127134
    128 UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
    129         std::vector<ptr<Attribute>>&& as )
    130 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    131 
    132 bool UnionInstType::isComplete() const { return base ? base->body : false; }
    133 
    134 // --- EnumInstType
    135 
    136 EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
    137         std::vector<ptr<Attribute>>&& as )
    138 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    139 
    140 bool EnumInstType::isComplete() const { return base ? base->body : false; }
     135template class SueInstType<StructDecl>;
     136template class SueInstType<UnionDecl>;
     137template class SueInstType<EnumDecl>;
    141138
    142139// --- TraitInstType
    143140
    144 TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
    145         std::vector<ptr<Attribute>>&& as )
    146 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    147 
    148 // --- TypeInstType
     141TraitInstType::TraitInstType(
     142        const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     143: BaseInstType( b->name, q, move(as) ), base( b ) {}
    149144
    150145void TypeInstType::set_base( const TypeDecl * b ) {
     
    158153
    159154TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    160 : Type( q ), types( std::move(ts) ), members() {
     155: Type( q ), types( move(ts) ), members() {
    161156        // This constructor is awkward. `TupleType` needs to contain objects so that members can be
    162157        // named, but members without initializer nodes end up getting constructors, which breaks
     
    173168        for ( const Type * ty : types ) {
    174169                members.emplace_back( new ObjectDecl{
    175                         CodeLocation{}, "", ty, new ListInit( CodeLocation{}, {}, {}, MaybeConstruct ),
     170                        CodeLocation{}, "", ty, new ListInit( CodeLocation{}, {}, {}, NoConstruct ),
    176171                        Storage::Classes{}, Linkage::Cforall } );
    177172        }
     173}
     174
     175bool isUnboundType(const Type * type) {
     176        if (auto typeInst = dynamic_cast<const TypeInstType *>(type)) {
     177                // xxx - look for a type name produced by renameTyVars.
     178
     179                // TODO: once TypeInstType representation is updated, it should properly check
     180                // if the context id is filled. this is a temporary hack for now
     181                return typeInst->formal_usage > 0;
     182        }
     183        return false;
    178184}
    179185
  • src/AST/Type.hpp

    r3c64c668 r58fe85a  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:56:46 2019
    13 // Update Count     : 5
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jul 23 14:15:00 2020
     13// Update Count     : 6
    1414//
    1515
     
    2929
    3030// Must be included in *all* AST classes; should be #undef'd at the end of the file
    31 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     31#define MUTATE_FRIEND \
     32    template<typename node_t> friend node_t * mutate(const node_t * node); \
     33        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3234
    3335namespace ast {
     36
     37template< typename T > class Pass;
    3438
    3539class Type : public Node {
     
    4448        bool is_volatile() const { return qualifiers.is_volatile; }
    4549        bool is_restrict() const { return qualifiers.is_restrict; }
    46         bool is_lvalue() const { return qualifiers.is_lvalue; }
    4750        bool is_mutex() const { return qualifiers.is_mutex; }
    4851        bool is_atomic() const { return qualifiers.is_atomic; }
     
    5154        Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; }
    5255        Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
    53         Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }
    5456        Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
    5557        Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
     
    163165        static const char *typeNames[];
    164166
    165         BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
     167        BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    166168        : Type(q, std::move(as)), kind(k) {}
    167169
     
    263265};
    264266
    265 /// Base type for potentially forall-qualified types
    266 class ParameterizedType : public Type {
    267 public:
    268         using ForallList = std::vector<ptr<TypeDecl>>;
    269 
    270         ForallList forall;
    271 
    272         ParameterizedType( ForallList&& fs = {}, CV::Qualifiers q = {},
    273                 std::vector<ptr<Attribute>> && as = {} )
    274         : Type(q, std::move(as)), forall(std::move(fs)) {}
    275 
    276         ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
    277         : Type(q, std::move(as)), forall() {}
    278 
    279 private:
    280         virtual ParameterizedType * clone() const override = 0;
    281         MUTATE_FRIEND
    282 };
    283 
    284267/// Function variable arguments flag
    285268enum ArgumentFlag { FixedArgs, VariableArgs };
    286269
    287270/// Type of a function `[R1, R2](*)(P1, P2, P3)`
    288 class FunctionType final : public ParameterizedType {
    289 public:
    290         std::vector<ptr<DeclWithType>> returns;
    291         std::vector<ptr<DeclWithType>> params;
     271class FunctionType final : public Type {
     272public:
     273        using ForallList = std::vector<ptr<TypeInstType>>;
     274        using AssertionList = std::vector<ptr<VariableExpr>>;
     275        ForallList forall;
     276        AssertionList assertions;
     277
     278        std::vector<ptr<Type>> returns;
     279        std::vector<ptr<Type>> params;
    292280
    293281        /// Does the function accept a variable number of arguments following the arguments specified
     
    299287
    300288        FunctionType( ArgumentFlag va = FixedArgs, CV::Qualifiers q = {} )
    301         : ParameterizedType(q), returns(), params(), isVarArgs(va) {}
     289        : Type(q), returns(), params(), isVarArgs(va) {}
     290
     291        FunctionType( const FunctionType & o ) = default;
    302292
    303293        /// true if either the parameters or return values contain a tttype
     
    313303
    314304/// base class for types that refer to types declared elsewhere (aggregates and typedefs)
    315 class ReferenceToType : public ParameterizedType {
     305class BaseInstType : public Type {
    316306public:
    317307        std::vector<ptr<Expr>> params;
     
    319309        bool hoistType = false;
    320310
    321         ReferenceToType( const std::string& n, CV::Qualifiers q = {},
    322                 std::vector<ptr<Attribute>> && as = {} )
    323         : ParameterizedType(q, std::move(as)), params(), name(n) {}
     311        BaseInstType(
     312                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     313        : Type(q, std::move(as)), params(), name(n) {}
     314
     315        BaseInstType(
     316                const std::string& n, std::vector<ptr<Expr>> && params,
     317                CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     318        : Type(q, std::move(as)), params(std::move(params)), name(n) {}
     319
     320        BaseInstType( const BaseInstType & o ) = default;
    324321
    325322        /// Gets aggregate declaration this type refers to
     
    329326
    330327private:
    331         virtual ReferenceToType * clone() const override = 0;
    332         MUTATE_FRIEND
    333 };
    334 
    335 /// instance of struct type
    336 class StructInstType final : public ReferenceToType {
    337 public:
    338         readonly<StructDecl> base;
    339 
    340         StructInstType( const std::string& n, CV::Qualifiers q = {},
    341                 std::vector<ptr<Attribute>> && as = {} )
    342         : ReferenceToType( n, q, std::move(as) ), base() {}
    343         StructInstType( const StructDecl * b, CV::Qualifiers q = {},
    344                 std::vector<ptr<Attribute>> && as = {} );
     328        virtual BaseInstType * clone() const override = 0;
     329        MUTATE_FRIEND
     330};
     331
     332// Common implementation for the SUE instance types. Not to be used directly.
     333template<typename decl_t>
     334class SueInstType final : public BaseInstType {
     335public:
     336        using base_type = decl_t;
     337        readonly<decl_t> base;
     338
     339        SueInstType(
     340                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     341        : BaseInstType( n, q, std::move(as) ), base() {}
     342
     343        SueInstType(
     344                const base_type * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
     345
     346        SueInstType(
     347                const base_type * b, std::vector<ptr<Expr>> && params,
     348                CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    345349
    346350        bool isComplete() const override;
    347351
    348         const StructDecl * aggr() const override { return base; }
    349 
    350         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    351 private:
    352         StructInstType * clone() const override { return new StructInstType{ *this }; }
    353         MUTATE_FRIEND
    354 };
    355 
    356 /// instance of union type
    357 class UnionInstType final : public ReferenceToType {
    358 public:
    359         readonly<UnionDecl> base;
    360 
    361         UnionInstType( const std::string& n, CV::Qualifiers q = {},
    362                 std::vector<ptr<Attribute>> && as = {} )
    363         : ReferenceToType( n, q, std::move(as) ), base() {}
    364         UnionInstType( const UnionDecl * b, CV::Qualifiers q = {},
    365                 std::vector<ptr<Attribute>> && as = {} );
    366 
    367         bool isComplete() const override;
    368 
    369         const UnionDecl * aggr() const override { return base; }
    370 
    371         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    372 private:
    373         UnionInstType * clone() const override { return new UnionInstType{ *this }; }
    374         MUTATE_FRIEND
    375 };
    376 
    377 /// instance of enum type
    378 class EnumInstType final : public ReferenceToType {
    379 public:
    380         readonly<EnumDecl> base;
    381 
    382         EnumInstType( const std::string& n, CV::Qualifiers q = {},
    383                 std::vector<ptr<Attribute>> && as = {} )
    384         : ReferenceToType( n, q, std::move(as) ), base() {}
    385         EnumInstType( const EnumDecl * b, CV::Qualifiers q = {},
    386                 std::vector<ptr<Attribute>> && as = {} );
    387 
    388         bool isComplete() const override;
    389 
    390         const EnumDecl * aggr() const override { return base; }
    391 
    392         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    393 private:
    394         EnumInstType * clone() const override { return new EnumInstType{ *this }; }
    395         MUTATE_FRIEND
    396 };
    397 
    398 /// instance of trait type
    399 class TraitInstType final : public ReferenceToType {
     352        const decl_t * aggr() const override { return base; }
     353
     354        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     355private:
     356        SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; }
     357        MUTATE_FRIEND
     358};
     359
     360/// An instance of a struct type.
     361using StructInstType = SueInstType<StructDecl>;
     362
     363/// An instance of a union type.
     364using UnionInstType = SueInstType<UnionDecl>;
     365
     366/// An instance of an enum type.
     367using EnumInstType = SueInstType<EnumDecl>;
     368
     369/// An instance of a trait type.
     370class TraitInstType final : public BaseInstType {
    400371public:
    401372        readonly<TraitDecl> base;
    402373
    403         TraitInstType( const std::string& n, CV::Qualifiers q = {},
    404                 std::vector<ptr<Attribute>> && as = {} )
    405         : ReferenceToType( n, q, std::move(as) ), base() {}
    406         TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
    407                 std::vector<ptr<Attribute>> && as = {} );
     374        TraitInstType(
     375                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
     376        : BaseInstType( n, q, std::move(as) ), base() {}
     377
     378        TraitInstType(
     379                const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    408380
    409381        // not meaningful for TraitInstType
     
    419391
    420392/// instance of named type alias (typedef or variable)
    421 class TypeInstType final : public ReferenceToType {
     393class TypeInstType final : public BaseInstType {
    422394public:
    423395        readonly<TypeDecl> base;
     396        // previously from renameTyVars; now directly use integer fields instead of synthesized strings
     397        // a nonzero value of formal_usage indicates a formal type (only used in function type)
     398        // a zero value of formal_usage indicates an actual type (referenced inside body of parametric structs and functions)
    424399        TypeDecl::Kind kind;
    425 
    426         TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
     400        int formal_usage = 0;
     401        int expr_id = 0;
     402
     403        // compact representation used for map lookups.
     404        struct TypeEnvKey {
     405                const TypeDecl * base;
     406                int formal_usage;
     407                int expr_id;
     408
     409                TypeEnvKey() = default;
     410                TypeEnvKey(const TypeDecl * base, int formal_usage = 0, int expr_id = 0): base(base), formal_usage(formal_usage), expr_id(expr_id) {}
     411                TypeEnvKey(const TypeInstType & inst): base(inst.base), formal_usage(inst.formal_usage), expr_id(inst.expr_id) {}
     412                std::string typeString() const { return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + base->name; }
     413                bool operator==(const TypeEnvKey & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
     414
     415        };
     416
     417        bool operator==(const TypeInstType & other) const { return base == other.base && formal_usage == other.formal_usage && expr_id == other.expr_id; }
     418
     419        TypeInstType(
     420                const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
    427421                std::vector<ptr<Attribute>> && as = {} )
    428         : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
     422        : BaseInstType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
    429423        TypeInstType( const std::string& n, TypeDecl::Kind k, CV::Qualifiers q = {},
    430424                std::vector<ptr<Attribute>> && as = {} )
    431         : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
     425        : BaseInstType( n, q, std::move(as) ), base(), kind( k ) {}
     426
     427        TypeInstType( const TypeInstType & o ) = default;
     428
     429        TypeInstType( const TypeEnvKey & key )
     430        : BaseInstType(key.base->name), base(key.base), kind(key.base->kind), formal_usage(key.formal_usage), expr_id(key.expr_id) {}
    432431
    433432        /// sets `base`, updating `kind` correctly
     
    440439
    441440        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     441
     442        std::string typeString() const {
     443                if (formal_usage > 0) return std::string("_") + std::to_string(formal_usage) + "_" + std::to_string(expr_id) + "_" + name;
     444                else return name;
     445        }
    442446private:
    443447        TypeInstType * clone() const override { return new TypeInstType{ *this }; }
     
    531535};
    532536
     537bool isUnboundType(const Type * type);
     538
     539}
     540
     541namespace std {
     542        template<>
     543        struct hash<typename ast::TypeInstType::TypeEnvKey> {
     544                size_t operator() (const ast::TypeInstType::TypeEnvKey & x) const {
     545                        const size_t p = 1000007;
     546                        size_t res = reinterpret_cast<size_t>(x.base);
     547                        res = p * res + x.formal_usage;
     548                        res = p * res + x.expr_id;
     549                        return res;
     550                }
     551        };
    533552}
    534553
  • src/AST/TypeEnvironment.cpp

    r3c64c668 r58fe85a  
    3434#include "ResolvExpr/Unify.h"      // for unifyInexact
    3535#include "Tuples/Tuples.h"         // for isTtype
     36#include "CompilationState.h"
    3637
    3738using ResolvExpr::WidenMode;
     
    5152        for ( const auto & i : open ) {
    5253                if ( first ) { first = false; } else { out << ' '; }
    53                 out << i.first << "(" << i.second << ")";
     54                out << i.first.typeString() << "(" << i.second << ")";
    5455        }
    5556}
    5657
    5758void print( std::ostream & out, const EqvClass & clz, Indenter indent ) {
    58         out << "( ";
    59         std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) );
     59        out << "(";
     60        bool first = true;
     61        for(const auto & var : clz.vars) {
     62                if(first) first = false;
     63                else out << " ";
     64
     65                if( deterministic_output ) out << "[unbound]";
     66                else out << "_" << var.formal_usage << "_" << var.expr_id << "_";
     67
     68                out << var.base->name;
     69        }
    6070        out << ")";
    61        
     71
    6272        if ( clz.bound ) {
    6373                out << " -> ";
     
    7282}
    7383
    74 const EqvClass * TypeEnvironment::lookup( const std::string & var ) const {
     84const EqvClass * TypeEnvironment::lookup( const TypeInstType::TypeEnvKey & var ) const {
    7585        for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) {
    7686                if ( i->vars.find( var ) != i->vars.end() ) return &*i;
     
    92102                                }
    93103                        }
    94                        
     104
    95105                        i = next;  // go to next node even if this removed
    96106                }
     
    98108}
    99109
    100 void TypeEnvironment::add( const ParameterizedType::ForallList & tyDecls ) {
    101         for ( const TypeDecl * tyDecl : tyDecls ) {
     110void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) {
     111        for ( auto & tyDecl : tyDecls ) {
    102112                env.emplace_back( tyDecl );
    103113        }
     
    112122void TypeEnvironment::writeToSubstitution( TypeSubstitution & sub ) const {
    113123        for ( const auto & clz : env ) {
    114                 std::string clzRep;
     124                TypeInstType::TypeEnvKey clzRep;
     125                bool first = true;
    115126                for ( const auto & var : clz.vars ) {
    116127                        if ( clz.bound ) {
    117128                                sub.add( var, clz.bound );
    118                         } else if ( clzRep.empty() ) {
     129                        } else if ( first ) {
    119130                                clzRep = var;
     131                                first = false;
    120132                        } else {
    121                                 sub.add( var, new TypeInstType{ clzRep, clz.data.kind } );
     133                                sub.add( var, new TypeInstType{ clzRep } );
    122134                        }
    123135                }
     
    134146        struct Occurs : public ast::WithVisitorRef<Occurs> {
    135147                bool result;
    136                 std::set< std::string > vars;
     148                std::unordered_set< TypeInstType::TypeEnvKey > vars;
    137149                const TypeEnvironment & tenv;
    138150
    139                 Occurs( const std::string & var, const TypeEnvironment & env )
     151                Occurs( const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env )
    140152                : result( false ), vars(), tenv( env ) {
    141153                        if ( const EqvClass * clz = tenv.lookup( var ) ) {
     
    147159
    148160                void previsit( const TypeInstType * typeInst ) {
    149                         if ( vars.count( typeInst->name ) ) {
     161                        if ( vars.count( *typeInst ) ) {
    150162                                result = true;
    151                         } else if ( const EqvClass * clz = tenv.lookup( typeInst->name ) ) {
     163                        } else if ( const EqvClass * clz = tenv.lookup( *typeInst ) ) {
    152164                                if ( clz->bound ) {
    153165                                        clz->bound->accept( *visitor );
     
    158170
    159171        /// true if `var` occurs in `ty` under `env`
    160         bool occurs( const Type * ty, const std::string & var, const TypeEnvironment & env ) {
     172        bool occurs( const Type * ty, const TypeInstType::TypeEnvKey & var, const TypeEnvironment & env ) {
    161173                Pass<Occurs> occur{ var, env };
    162174                maybe_accept( ty, occur );
    163                 return occur.pass.result;
    164         }
    165 }
    166 
    167 bool TypeEnvironment::combine( 
     175                return occur.core.result;
     176        }
     177}
     178
     179bool TypeEnvironment::combine(
    168180                const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) {
    169181        // short-circuit easy cases
     
    199211                                auto st = internal_lookup( *vt );
    200212                                if ( st == env.end() ) {
    201                                         // unbound, safe to add if occurs 
     213                                        // unbound, safe to add if occurs
    202214                                        if ( r.bound && occurs( r.bound, *vt, *this ) ) return false;
    203215                                        r.vars.emplace( *vt );
     
    266278}
    267279
    268 bool TypeEnvironment::bindVar( 
    269                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
    270                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 
    271                 const SymbolTable & symtab 
     280bool TypeEnvironment::bindVar(
     281                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
     282                AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen,
     283                const SymbolTable & symtab
    272284) {
    273285        // remove references from bound type, so that type variables can only bind to value types
    274286        ptr<Type> target = bindTo->stripReferences();
    275         auto tyvar = open.find( typeInst->name );
     287        auto tyvar = open.find( *typeInst );
    276288        assert( tyvar != open.end() );
    277289        if ( ! tyVarCompatible( tyvar->second, target ) ) return false;
    278         if ( occurs( target, typeInst->name, *this ) ) return false;
    279 
    280         auto it = internal_lookup( typeInst->name );
     290        if ( occurs( target, *typeInst, *this ) ) return false;
     291
     292        auto it = internal_lookup( *typeInst );
    281293        if ( it != env.end() ) {
    282294                if ( it->bound ) {
     
    286298                        ptr<Type> newType = it->bound;
    287299                        reset_qualifiers( newType, typeInst->qualifiers );
    288                         if ( unifyInexact( 
    289                                         newType, target, *this, need, have, open, 
     300                        if ( unifyInexact(
     301                                        newType, target, *this, need, have, open,
    290302                                        widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) {
    291303                                if ( common ) {
     
    300312                }
    301313        } else {
    302                 env.emplace_back( 
    303                         typeInst->name, target, widen.first && widen.second, data );
     314                env.emplace_back(
     315                        *typeInst, target, widen.first && widen.second, data );
    304316        }
    305317        return true;
    306318}
    307319
    308 bool TypeEnvironment::bindVarToVar( 
    309                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
    310                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 
    311                 WidenMode widen, const SymbolTable & symtab 
     320bool TypeEnvironment::bindVarToVar(
     321                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
     322                AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
     323                WidenMode widen, const SymbolTable & symtab
    312324) {
    313         auto c1 = internal_lookup( var1->name );
    314         auto c2 = internal_lookup( var2->name );
    315        
     325        auto c1 = internal_lookup( *var1 );
     326        auto c2 = internal_lookup( *var2 );
     327
    316328        // exit early if variables already bound together
    317329        if ( c1 != env.end() && c1 == c2 ) {
     
    326338        if ( c1 != env.end() ) {
    327339                if ( c1->bound ) {
    328                         if ( occurs( c1->bound, var2->name, *this ) ) return false;
     340                        if ( occurs( c1->bound, *var2, *this ) ) return false;
    329341                        type1 = c1->bound;
    330342                }
     
    333345        if ( c2 != env.end() ) {
    334346                if ( c2->bound ) {
    335                         if ( occurs( c2->bound, var1->name, *this ) ) return false;
     347                        if ( occurs( c2->bound, *var1, *this ) ) return false;
    336348                        type2 = c2->bound;
    337349                }
     
    371383        } else if ( c1 != env.end() ) {
    372384                // var2 unbound, add to env[c1]
    373                 c1->vars.emplace( var2->name );
     385                c1->vars.emplace( *var2 );
    374386                c1->allowWidening = widen1;
    375387                c1->data.isComplete |= data.isComplete;
    376388        } else if ( c2 != env.end() ) {
    377389                // var1 unbound, add to env[c2]
    378                 c2->vars.emplace( var1->name );
     390                c2->vars.emplace( *var1 );
    379391                c2->allowWidening = widen2;
    380392                c2->data.isComplete |= data.isComplete;
    381393        } else {
    382394                // neither var bound, create new class
    383                 env.emplace_back( var1->name, var2->name, widen1 && widen2, data );
     395                env.emplace_back( *var1, *var2, widen1 && widen2, data );
    384396        }
    385397
     
    396408}
    397409
    398 bool TypeEnvironment::mergeBound( 
     410bool TypeEnvironment::mergeBound(
    399411                EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) {
    400412        if ( from.bound ) {
     
    406418                        AssertionSet need, have;
    407419
    408                         if ( unifyInexact( 
     420                        if ( unifyInexact(
    409421                                        toType, fromType, *this, need, have, open, widen, symtab, common ) ) {
    410422                                // unifies, set common type if necessary
     
    424436}
    425437
    426 bool TypeEnvironment::mergeClasses( 
     438bool TypeEnvironment::mergeClasses(
    427439        ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab
    428440) {
     
    445457}
    446458
    447 TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string & var ) {
     459TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const TypeInstType::TypeEnvKey & var ) {
    448460        for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) {
    449461                if ( i->vars.count( var ) ) return i;
  • src/AST/TypeEnvironment.hpp

    r3c64c668 r58fe85a  
    3737/// Adding this comparison operator significantly improves assertion satisfaction run time for
    3838/// some cases. The current satisfaction algorithm's speed partially depends on the order of
    39 /// assertions. Assertions which have fewer possible matches should appear before assertions 
    40 /// which have more possible matches. This seems to imply that this could be further improved 
    41 /// by providing an indexer as an additional argument and ordering based on the number of 
     39/// assertions. Assertions which have fewer possible matches should appear before assertions
     40/// which have more possible matches. This seems to imply that this could be further improved
     41/// by providing an indexer as an additional argument and ordering based on the number of
    4242/// matches of the same kind (object, function) for the names of the declarations.
    4343///
    44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 
     44/// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
    4545/// comparator.
    4646///
    47 /// Note: since this compares pointers for position, minor changes in the source file that 
    48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 
    49 /// placement of a line directive can reorder type pointers with respect to each other so that 
    50 /// assertions are seen in different orders, causing a potentially different number of 
    51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 
    52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 
    53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 
    54 /// name instead of type as the second comparator, but this causes some assertions to never be 
     47/// Note: since this compares pointers for position, minor changes in the source file that
     48/// affect memory layout can alter compilation time in unpredictable ways. For example, the
     49/// placement of a line directive can reorder type pointers with respect to each other so that
     50/// assertions are seen in different orders, causing a potentially different number of
     51/// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27
     52/// seconds by reordering line directives alone, so it would be nice to fix this comparison so
     53/// that assertions compare more consistently. I've tried to modify this to compare on mangle
     54/// name instead of type as the second comparator, but this causes some assertions to never be
    5555/// recorded. More investigation is needed.
    5656struct AssertCompare {
    57         bool operator()( const DeclWithType * d1, const DeclWithType * d2 ) const {
    58                 int cmp = d1->name.compare( d2->name );
    59                 return cmp < 0 || ( cmp == 0 && d1->get_type() < d2->get_type() );
     57        bool operator()( const VariableExpr * d1, const VariableExpr * d2 ) const {
     58                int cmp = d1->var->name.compare( d2->var->name );
     59                return cmp < 0 || ( cmp == 0 && d1->result < d2->result );
    6060        }
    6161};
     
    7070
    7171/// Set of assertions pending satisfaction
    72 using AssertionSet = std::map< readonly<DeclWithType>, AssertionSetValue, AssertCompare >;
     72using AssertionSet = std::map< const VariableExpr *, AssertionSetValue, AssertCompare >;
    7373
    7474/// Set of open variables
    75 using OpenVarSet = std::unordered_map< std::string, TypeDecl::Data >;
     75using OpenVarSet = std::unordered_map< TypeInstType::TypeEnvKey, TypeDecl::Data >;
    7676
    7777/// Merges one set of open vars into another
     
    8686void print( std::ostream &, const OpenVarSet &, Indenter indent = {} );
    8787
    88 /// Represents an equivalence class of bound type variables, optionally with the concrete type 
     88/// Represents an equivalence class of bound type variables, optionally with the concrete type
    8989/// they bind to.
    9090struct EqvClass {
    91         std::set< std::string > vars;
     91        std::unordered_set< TypeInstType::TypeEnvKey > vars;
    9292        ptr<Type> bound;
    9393        bool allowWidening;
     
    9595
    9696        EqvClass() : vars(), bound(), allowWidening( true ), data() {}
    97        
     97
    9898        /// Copy-with-bound constructor
    99         EqvClass( const EqvClass & o, const Type * b ) 
     99        EqvClass( const EqvClass & o, const Type * b )
    100100        : vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {}
    101101
    102102        /// Singleton class constructor from TypeDecl
    103         EqvClass( const TypeDecl * decl )
    104         : vars{ decl->name }, bound(), allowWidening( true ), data( decl ) {}
     103        EqvClass( const TypeInstType * inst )
     104        : vars{ *inst }, bound(), allowWidening( true ), data( inst->base ) {}
    105105
    106106        /// Singleton class constructor from substitution
    107         EqvClass( const std::string & v, const Type * b )
     107        EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b )
    108108        : vars{ v }, bound( b ), allowWidening( false ), data( TypeDecl::Dtype, false ) {}
    109109
    110110        /// Single-var constructor (strips qualifiers from bound type)
    111         EqvClass( const std::string & v, const Type * b, bool w, const TypeDecl::Data & d )
     111        EqvClass( const TypeInstType::TypeEnvKey & v, const Type * b, bool w, const TypeDecl::Data & d )
    112112        : vars{ v }, bound( b ), allowWidening( w ), data( d ) {
    113113                reset_qualifiers( bound );
     
    115115
    116116        /// Double-var constructor
    117         EqvClass( const std::string & v, const std::string & u, bool w, const TypeDecl::Data & d )
     117        EqvClass( const TypeInstType::TypeEnvKey & v, const TypeInstType::TypeEnvKey & u, bool w, const TypeDecl::Data & d )
    118118        : vars{ v, u }, bound(), allowWidening( w ), data( d ) {}
    119119
     
    131131public:
    132132        /// Finds the equivalence class containing a variable; nullptr for none such
    133         const EqvClass * lookup( const std::string & var ) const;
     133        const EqvClass * lookup( const TypeInstType::TypeEnvKey & var ) const;
    134134
    135135        /// Add a new equivalence class for each type variable
    136         void add( const ParameterizedType::ForallList & tyDecls );
     136        void add( const FunctionType::ForallList & tyDecls );
    137137
    138138        /// Add a new equivalence class for each branch of the substitution, checking for conflicts
     
    142142        void writeToSubstitution( TypeSubstitution & sub ) const;
    143143
    144         template< typename node_t, enum Node::ref_type ref_t >
    145         int apply( ptr_base< node_t, ref_t > & type ) const {
     144        template< typename node_t >
     145        auto apply( node_t && type ) const {
    146146                TypeSubstitution sub;
    147147                writeToSubstitution( sub );
    148                 return sub.apply( type );
    149         }
    150 
    151         template< typename node_t, enum Node::ref_type ref_t >
    152         int applyFree( ptr_base< node_t, ref_t > & type ) const {
     148                return sub.apply( std::forward<node_t>(type) );
     149        }
     150
     151        template< typename node_t >
     152        auto applyFree( node_t && type ) const {
    153153                TypeSubstitution sub;
    154154                writeToSubstitution( sub );
    155                 return sub.applyFree( type );
     155                return sub.applyFree( std::forward<node_t>(type) );
    156156        }
    157157
     
    172172        void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars );
    173173
    174         /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 
     174        /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if
    175175        /// needed. Returns false on failure.
    176         bool bindVar( 
    177                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
    178                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
     176        bool bindVar(
     177                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
     178                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    179179                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    180        
    181         /// Binds the type classes represented by `var1` and `var2` together; will add one or both 
     180
     181        /// Binds the type classes represented by `var1` and `var2` together; will add one or both
    182182        /// classes if needed. Returns false on failure.
    183         bool bindVarToVar( 
    184                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
    185                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
     183        bool bindVarToVar(
     184                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
     185                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    186186                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    187187
     
    198198
    199199        /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails
    200         bool mergeBound( 
     200        bool mergeBound(
    201201                EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab );
    202202
    203203        /// Merges two type classes from local environment, returning false if fails
    204         bool mergeClasses( 
    205                 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 
     204        bool mergeClasses(
     205                ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars,
    206206                const SymbolTable & symtab );
    207207
    208208        /// Private lookup API; returns array index of string, or env.size() for not found
    209         ClassList::iterator internal_lookup( const std::string & );
     209        ClassList::iterator internal_lookup( const TypeInstType::TypeEnvKey & );
    210210};
    211211
  • src/AST/TypeSubstitution.cpp

    r3c64c668 r58fe85a  
    1919namespace ast {
    2020
     21
     22// size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
     23
    2124TypeSubstitution::TypeSubstitution() {
    2225}
     
    3639void TypeSubstitution::initialize( const TypeSubstitution &src, TypeSubstitution &dest ) {
    3740        dest.typeEnv.clear();
    38         dest.varEnv.clear();
    3941        dest.add( src );
    4042}
     
    4446                typeEnv[ i->first ] = i->second;
    4547        } // for
    46         for ( VarEnvType::const_iterator i = other.varEnv.begin(); i != other.varEnv.end(); ++i ) {
    47                 varEnv[ i->first ] = i->second;
    48         } // for
    4948}
    5049
    51 void TypeSubstitution::add( std::string formalType, const Type *actualType ) {
    52         typeEnv[ formalType ] = actualType;
     50void TypeSubstitution::add( const TypeInstType * formalType, const Type *actualType ) {
     51        typeEnv[ *formalType ] = actualType;
    5352}
    5453
    55 void TypeSubstitution::addVar( std::string formalExpr, const Expr *actualExpr ) {
    56         varEnv[ formalExpr ] = actualExpr;
     54void TypeSubstitution::add( const TypeInstType::TypeEnvKey & key, const Type * actualType) {
     55        typeEnv[ key ] = actualType;
    5756}
    5857
    59 void TypeSubstitution::remove( std::string formalType ) {
    60         TypeEnvType::iterator i = typeEnv.find( formalType );
     58void TypeSubstitution::remove( const TypeInstType * formalType ) {
     59        TypeEnvType::iterator i = typeEnv.find( *formalType );
    6160        if ( i != typeEnv.end() ) {
    62                 typeEnv.erase( formalType );
     61                typeEnv.erase( *formalType );
    6362        } // if
    6463}
    6564
    66 const Type *TypeSubstitution::lookup( std::string formalType ) const {
    67         TypeEnvType::const_iterator i = typeEnv.find( formalType );
     65const Type *TypeSubstitution::lookup( const TypeInstType * formalType ) const {
     66        TypeEnvType::const_iterator i = typeEnv.find( *formalType );
    6867
    6968        // break on not in substitution set
     
    7271        // attempt to transitively follow TypeInstType links.
    7372        while ( const TypeInstType *actualType = i->second.as<TypeInstType>()) {
    74                 const std::string& typeName = actualType->name;
    75 
    7673                // break cycles in the transitive follow
    77                 if ( formalType == typeName ) break;
     74                if ( *formalType == *actualType ) break;
    7875
    7976                // Look for the type this maps to, returning previous mapping if none-such
    80                 i = typeEnv.find( typeName );
     77                i = typeEnv.find( *actualType );
    8178                if ( i == typeEnv.end() ) return actualType;
    8279        }
     
    8784
    8885bool TypeSubstitution::empty() const {
    89         return typeEnv.empty() && varEnv.empty();
     86        return typeEnv.empty();
    9087}
    9188
    9289namespace {
    9390        struct EnvTrimmer {
    94                 ptr<TypeSubstitution> env;
     91                const TypeSubstitution * env;
    9592                TypeSubstitution * newEnv;
    9693                EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
    97                 void previsit( TypeDecl * tyDecl ) {
     94                void previsit( FunctionType * ftype ) {
    9895                        // transfer known bindings for seen type variables
    99                         if ( const Type * t = env->lookup( tyDecl->name ) ) {
    100                                 newEnv->add( tyDecl->name, t );
     96                        for (auto & formal : ftype->forall) {
     97                                if ( const Type * t = env->lookup( formal ) ) {
     98                                        newEnv->add( formal, t );
     99                                }
    101100                        }
    102101                }
     
    108107        if ( env ) {
    109108                TypeSubstitution * newEnv = new TypeSubstitution();
    110 #if TIME_TO_CONVERT_PASSES
    111109                Pass<EnvTrimmer> trimmer( env, newEnv );
    112110                expr->accept( trimmer );
    113 #else
    114                 (void)expr;
    115                 (void)env;
    116 #endif
    117111                return newEnv;
    118112        }
     
    121115
    122116void TypeSubstitution::normalize() {
    123 #if TIME_TO_CONVERT_PASSES
    124         PassVisitor<Substituter> sub( *this, true );
     117        Pass<Substituter> sub( *this, true );
    125118        do {
    126                 sub.pass.subCount = 0;
    127                 sub.pass.freeOnly = true;
     119                sub.core.subCount = 0;
     120                sub.core.freeOnly = true;
    128121                for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
    129                         i->second = i->second->acceptMutator( sub );
     122                        i->second = i->second->accept( sub );
    130123                }
    131         } while ( sub.pass.subCount );
    132 #endif
     124        } while ( sub.core.subCount );
    133125}
    134126
    135 #if TIME_TO_CONVERT_PASSES
    136 
    137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
    138         BoundVarsType::const_iterator bound = boundVars.find( inst->name );
     127const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
     128        BoundVarsType::const_iterator bound = boundVars.find( *inst );
    139129        if ( bound != boundVars.end() ) return inst;
    140130
    141         TypeEnvType::const_iterator i = sub.typeEnv.find( inst->name );
     131        TypeEnvType::const_iterator i = sub.typeEnv.find( *inst );
    142132        if ( i == sub.typeEnv.end() ) {
    143133                return inst;
     
    146136                // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
    147137                // TODO: investigate preventing type variables from being bound to themselves in the first place.
    148                 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
    149                         if ( inst->name == replacement->name ) {
     138                if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
     139                        if ( *inst == *replacement ) {
    150140                                return inst;
    151141                        }
     
    153143                // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
    154144                subCount++;
    155                 Type * newtype = i->second->clone();
    156                 newtype->get_qualifiers() |= inst->get_qualifiers();
    157                 delete inst;
    158                 // Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
    159                 return newtype->acceptMutator( *visitor );
     145                ptr<Type> newType = i->second; // force clone if needed
     146                add_qualifiers( newType, inst->qualifiers );
     147                // Note: need to recursively apply substitution to the new type because normalize does not
     148                // substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
     149                newType = newType->accept( *visitor );
     150                return newType.release();
    160151        } // if
    161152}
    162153
    163 Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
    164         VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
    165         if ( i == sub.varEnv.end() ) {
    166                 return nameExpr;
    167         } else {
    168                 subCount++;
    169                 delete nameExpr;
    170                 return i->second->clone();
    171         } // if
    172 }
    173 
    174 void TypeSubstitution::Substituter::premutate( Type * type ) {
     154void TypeSubstitution::Substituter::previsit( const FunctionType * ptype ) {
    175155        GuardValue( boundVars );
    176156        // bind type variables from forall-qualifiers
    177157        if ( freeOnly ) {
    178                 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
    179                         boundVars.insert( (*tyvar)->name );
     158                for ( auto & tyvar : ptype->forall ) {
     159                                boundVars.insert( *tyvar );
    180160                } // for
    181161        } // if
    182162}
    183163
    184 template< typename TypeClass >
    185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
     164/*
     165void TypeSubstitution::Substituter::handleAggregateType( const BaseInstType * type ) {
    186166        GuardValue( boundVars );
    187167        // bind type variables from forall-qualifiers
    188168        if ( freeOnly ) {
    189                 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
    190                         boundVars.insert( (*tyvar)->name );
    191                 } // for
    192169                // bind type variables from generic type instantiations
    193                 std::list< TypeDecl* > *baseParameters = type->get_baseParameters();
    194                 if ( baseParameters && ! type->parameters.empty() ) {
    195                         for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) {
    196                                 boundVars.insert( (*tyvar)->name );
    197                         } // for
    198                 } // if
     170                if ( auto decl = type->aggr() ) {
     171                        if ( ! type->params.empty() ) {
     172                                for ( const TypeDecl * tyvar : decl->params ) {
     173                                        boundVars.insert( *tyvar );
     174                                } // for
     175                        } // if
     176                }
    199177        } // if
    200178}
    201179
    202 void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
     180void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
    203181        handleAggregateType( aggregateUseType );
    204182}
    205183
    206 void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
     184void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
    207185        handleAggregateType( aggregateUseType );
    208186}
    209 
    210 #endif
     187*/
    211188
    212189} // namespace ast
  • src/AST/TypeSubstitution.hpp

    r3c64c668 r58fe85a  
    4444        TypeSubstitution &operator=( const TypeSubstitution &other );
    4545
    46         template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const;
    47         template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const;
     46        template< typename SynTreeClass >
     47        struct ApplyResult {
     48                ast::ptr<SynTreeClass> node;
     49                int count;
     50        };
     51
     52        template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const;
     53        template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const;
    4854
    4955        template< typename node_t, enum Node::ref_type ref_t >
    5056        int apply( ptr_base< node_t, ref_t > & input ) const {
    5157                const node_t * p = input.get();
    52                 int ret = apply(p);
    53                 input = p;
    54                 return ret;
     58                auto ret = apply(p);
     59                input = ret.node;
     60                return ret.count;
    5561        }
    5662
     
    5864        int applyFree( ptr_base< node_t, ref_t > & input ) const {
    5965                const node_t * p = input.get();
    60                 int ret = applyFree(p);
    61                 input = p;
    62                 return ret;
     66                auto ret = applyFree(p);
     67                input = ret.node;
     68                return ret.count;
    6369        }
    6470
    65         void add( std::string formalType, const Type *actualType );
     71        void add( const TypeInstType * formalType, const Type *actualType );
     72        void add( const TypeInstType::TypeEnvKey & key, const Type *actualType );
    6673        void add( const TypeSubstitution &other );
    67         void remove( std::string formalType );
    68         const Type *lookup( std::string formalType ) const;
     74        void remove( const TypeInstType * formalType );
     75        const Type *lookup( const TypeInstType * formalType ) const;
    6976        bool empty() const;
    70 
    71         void addVar( std::string formalExpr, const Expr *actualExpr );
    7277
    7378        template< typename FormalIterator, typename ActualIterator >
     
    9297        void initialize( const TypeSubstitution &src, TypeSubstitution &dest );
    9398
    94         template<typename pass_type>
     99        template<typename core_t>
    95100        friend class Pass;
    96101
    97         typedef std::unordered_map< std::string, ptr<Type> > TypeEnvType;
    98         typedef std::unordered_map< std::string, ptr<Expr> > VarEnvType;
     102        typedef std::unordered_map< TypeInstType::TypeEnvKey, ptr<Type> > TypeEnvType;
    99103        TypeEnvType typeEnv;
    100         VarEnvType varEnv;
    101104
    102105  public:
     
    107110        auto   end() const -> decltype( typeEnv.  end() ) { return typeEnv.  end(); }
    108111
    109         auto beginVar()       -> decltype( varEnv.begin() ) { return varEnv.begin(); }
    110         auto   endVar()       -> decltype( varEnv.  end() ) { return varEnv.  end(); }
    111         auto beginVar() const -> decltype( varEnv.begin() ) { return varEnv.begin(); }
    112         auto   endVar() const -> decltype( varEnv.  end() ) { return varEnv.  end(); }
    113112};
    114113
     114// this is the only place where type parameters outside a function formal may be substituted.
    115115template< typename FormalIterator, typename ActualIterator >
    116116void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
     
    123123                        if ( const TypeExpr *actual = actualIt->template as<TypeExpr>() ) {
    124124                                if ( formal->name != "" ) {
    125                                         typeEnv[ formal->name ] = actual->type;
     125                                        typeEnv[ formal ] = actual->type;
    126126                                } // if
    127127                        } else {
     
    129129                        } // if
    130130                } else {
    131                         // TODO: type check the formal and actual parameters
    132                         if ( (*formalIt)->name != "" ) {
    133                                 varEnv[ (*formalIt)->name ] = *actualIt;
    134                         } // if
     131                       
    135132                } // if
    136133        } // for
    137134}
     135
     136
    138137
    139138template< typename FormalIterator, typename ActualIterator >
     
    142141}
    143142
     143
    144144} // namespace ast
    145145
     
    147147// PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
    148148#include "Pass.hpp"
     149#include "Copy.hpp"
    149150
    150151namespace ast {
    151152
    152153// definitition must happen after PassVisitor is included so that WithGuards can be used
    153 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
     154struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter>, public PureVisitor {
     155                static size_t traceId;
    154156
    155157                Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    156158
    157 #if TIME_TO_CONVERT_PASSES
    158 
    159                 Type * postmutate( TypeInstType * aggregateUseType );
    160                 Expression * postmutate( NameExpr * nameExpr );
     159                const Type * postvisit( const TypeInstType * aggregateUseType );
    161160
    162161                /// Records type variable bindings from forall-statements
    163                 void premutate( Type * type );
     162                void previsit( const FunctionType * type );
    164163                /// Records type variable bindings from forall-statements and instantiations of generic types
    165                 template< typename TypeClass > void handleAggregateType( TypeClass * type );
     164                // void handleAggregateType( const BaseInstType * type );
    166165
    167                 void premutate( StructInstType * aggregateUseType );
    168                 void premutate( UnionInstType * aggregateUseType );
    169 
    170 #endif
     166                // void previsit( const StructInstType * aggregateUseType );
     167                // void previsit( const UnionInstType * aggregateUseType );
    171168
    172169                const TypeSubstitution & sub;
    173170                int subCount = 0;
    174171                bool freeOnly;
    175                 typedef std::unordered_set< std::string > BoundVarsType;
     172                typedef std::unordered_set< TypeInstType::TypeEnvKey > BoundVarsType;
    176173                BoundVarsType boundVars;
    177174
     
    179176
    180177template< typename SynTreeClass >
    181 int TypeSubstitution::apply( const SynTreeClass *& input ) const {
     178TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {
    182179        assert( input );
    183180        Pass<Substituter> sub( *this, false );
    184181        input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    185 ///     std::cerr << "substitution result is: ";
    186 ///     newType->print( std::cerr );
    187 ///     std::cerr << std::endl;
    188         return sub.pass.subCount;
     182        return { input, sub.core.subCount };
    189183}
    190184
    191185template< typename SynTreeClass >
    192 int TypeSubstitution::applyFree( const SynTreeClass *& input ) const {
     186TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {
    193187        assert( input );
    194188        Pass<Substituter> sub( *this, true );
    195189        input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    196 ///     std::cerr << "substitution result is: ";
    197 ///     newType->print( std::cerr );
    198 ///     std::cerr << std::endl;
    199         return sub.pass.subCount;
     190        return { input, sub.core.subCount };
    200191}
    201192
  • src/AST/Visitor.hpp

    r3c64c668 r58fe85a  
    4747    virtual const ast::Stmt *             visit( const ast::CatchStmt            * ) = 0;
    4848    virtual const ast::Stmt *             visit( const ast::FinallyStmt          * ) = 0;
     49    virtual const ast::Stmt *             visit( const ast::SuspendStmt          * ) = 0;
    4950    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
    5051    virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
  • src/AST/module.mk

    r3c64c668 r58fe85a  
    1717SRC_AST = \
    1818        AST/AssertAcyclic.cpp \
     19        AST/AssertAcyclic.hpp \
    1920        AST/Attribute.cpp \
     21        AST/Attribute.hpp \
     22        AST/Bitfield.hpp \
     23        AST/Chain.hpp \
    2024        AST/Convert.cpp \
     25        AST/Convert.hpp \
     26        AST/Copy.hpp \
     27        AST/CVQualifiers.hpp \
    2128        AST/Decl.cpp \
     29        AST/Decl.hpp \
    2230        AST/DeclReplacer.cpp \
     31        AST/DeclReplacer.hpp \
     32        AST/Eval.hpp \
    2333        AST/Expr.cpp \
     34        AST/Expr.hpp \
     35        AST/FunctionSpec.hpp \
     36        AST/Fwd.hpp \
    2437        AST/GenericSubstitution.cpp \
     38        AST/GenericSubstitution.hpp \
    2539        AST/Init.cpp \
     40        AST/Init.hpp \
     41        AST/Label.hpp \
    2642        AST/LinkageSpec.cpp \
     43        AST/LinkageSpec.hpp \
    2744        AST/Node.cpp \
     45        AST/Node.hpp \
     46        AST/ParseNode.hpp \
    2847        AST/Pass.cpp \
     48        AST/Pass.hpp \
     49        AST/Pass.impl.hpp \
     50        AST/Pass.proto.hpp \
    2951        AST/Print.cpp \
     52        AST/Print.hpp \
    3053        AST/Stmt.cpp \
     54        AST/Stmt.hpp \
     55        AST/StorageClasses.hpp \
    3156        AST/SymbolTable.cpp \
     57        AST/SymbolTable.hpp \
     58        AST/TranslationUnit.hpp \
    3259        AST/Type.cpp \
     60        AST/Type.hpp \
    3361        AST/TypeEnvironment.cpp \
    34         AST/TypeSubstitution.cpp
     62        AST/TypeEnvironment.hpp \
     63        AST/TypeSubstitution.cpp \
     64        AST/TypeSubstitution.hpp \
     65        AST/Visitor.hpp
    3566
    3667SRC += $(SRC_AST)
  • src/AST/porting.md

    r3c64c668 r58fe85a  
    3030  * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0`
    3131* `PassVisitor` is replaced with `ast::Pass`
     32  * Most one shot uses can use `ast::Pass::run` and `ast::Pass::read`.
     33
     34`WithConstTypeSubstitution`
     35* `env` => `typeSubs`
    3236
    3337## Structural Changes ##
     
    4751      template<typename node_t>
    4852      friend node_t * mutate(const node_t * node);
     53      template<typename node_t>
     54      friend node_t * shallowCopy(const node_t * node);
     55    or equilant.
     56* You should use the `mutate` function where possible as it avoids extra copies.
     57  * If you must copy use `shallowCopy` or `deepCopy` as required.
    4958
    5059All leaves of the `Node` inheritance tree are now declared `final`
     
    141150  * allows `newObject` as just default settings
    142151
     152`FunctionDecl`
     153* `params` and `returns` added.
     154  * Contain the declarations of the parameters and return variables.
     155  * Types should match (even be shared with) the fields of `type`.
     156
    143157`NamedTypeDecl`
    144158* `parameters` => `params`
     
    149163`AggregateDecl`
    150164* `parameters` => `params`
     165
     166`StructDecl`
     167* `makeInst` replaced by better constructor on `StructInstType`.
    151168
    152169`Expr`
     
    240257* **TODO** move `kind`, `typeNames` into code generator
    241258
    242 `ReferenceToType`
     259`ReferenceToType` => `BaseInstType`
    243260* deleted `get_baseParameters()` from children
    244261  * replace with `aggr() ? aggr()->params : nullptr`
     
    256273* `returnVals` => `returns`
    257274* `parameters` => `params`
     275  * Both now just point at types.
    258276* `bool isVarArgs;` => `enum ArgumentFlag { FixedArgs, VariableArgs }; ArgumentFlag isVarArgs;`
     277
     278`SueInstType`
     279* Template class, with specializations and using to implement some other types:
     280  * `StructInstType`, `UnionInstType` & `EnumInstType`
    259281
    260282`TypeInstType`
  • src/CodeGen/CodeGenerator.cc

    r3c64c668 r58fe85a  
    120120                // GCC builtins should always be printed unmangled
    121121                if ( options.pretty || decl->linkage.is_gcc_builtin ) return decl->name;
    122                 if ( decl->mangleName != "" ) {
     122                if ( LinkageSpec::isMangled(decl->linkage) && decl->mangleName != "" ) {
    123123                        // need to incorporate scope level in order to differentiate names for destructors
    124124                        return decl->get_scopedMangleName();
  • src/CodeGen/FixMain.cc

    r3c64c668 r58fe85a  
    2626#include "SynTree/Declaration.h"   // for FunctionDecl, operator<<
    2727#include "SynTree/Type.h"          // for FunctionType
     28#include "SymTab/Mangler.h"
    2829
    2930namespace CodeGen {
     
    4748                if( main_signature ) {
    4849                        os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
     50                        main_signature->mangleName = SymTab::Mangler::mangle(main_signature.get());
    4951
    5052                        os << main_signature->get_scopedMangleName() << "(";
  • src/CodeGen/FixNames.cc

    r3c64c668 r58fe85a  
    3131#include "SynTree/Type.h"          // for Type, BasicType, Type::Qualifiers
    3232#include "SynTree/Visitor.h"       // for Visitor, acceptAll
     33#include "CompilationState.h"
    3334
    3435namespace CodeGen {
     
    102103                if ( dwt->get_name() != "" ) {
    103104                        if ( LinkageSpec::isMangled( dwt->get_linkage() ) ) {
    104                                 dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
     105                                if (!useNewAST) {
     106                                        dwt->set_mangleName( SymTab::Mangler::mangle( dwt ) );
     107                                }
    105108                                dwt->set_scopeLevel( scopeLevel );
    106109                        } // if
  • src/CodeGen/module.mk

    r3c64c668 r58fe85a  
    2020SRC_CODEGEN = \
    2121        CodeGen/CodeGenerator.cc \
     22        CodeGen/CodeGenerator.h \
    2223        CodeGen/FixMain.cc \
     24        CodeGen/FixMain.h \
    2325        CodeGen/GenType.cc \
    24         CodeGen/OperatorTable.cc
     26        CodeGen/GenType.h \
     27        CodeGen/OperatorTable.cc \
     28        CodeGen/OperatorTable.h \
     29        CodeGen/Options.h
    2530
    26 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/FixNames.cc
     31SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/Generate.h CodeGen/FixNames.cc CodeGen/FixNames.h
    2732SRCDEMANGLE += $(SRC_CODEGEN)
  • src/CodeTools/TrackLoc.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Tues May 2 15:46:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed May 3 14:43:00 2017
    13 // Update Count     : 0
     12// Last Modified On : Fri Nov 27 18:00:00 2020
     13// Update Count     : 1
    1414//
    1515
     
    2222#include <string>                    // for operator<<, string
    2323#include <typeindex>                 // for type_index
     24#include <vector>                    // for vector
    2425
    2526#include "Common/PassVisitor.h"      // for PassVisitor
     
    3738                CodeLocation *lastNode;
    3839
    39                 std::stack< CodeLocation * > parents;
     40                std::stack< CodeLocation *, std::vector< CodeLocation * > > parents;
    4041        public:
    4142                LocationPrinter(size_t printLevel) :
  • src/CodeTools/module.mk

    r3c64c668 r58fe85a  
    1515###############################################################################
    1616
    17 SRC += CodeTools/DeclStats.cc \
     17SRC += \
     18        CodeTools/DeclStats.cc \
     19        CodeTools/DeclStats.h \
    1820        CodeTools/ResolvProtoDump.cc \
    19         CodeTools/TrackLoc.cc
     21        CodeTools/ResolvProtoDump.h \
     22        CodeTools/TrackLoc.cc \
     23        CodeTools/TrackLoc.h
  • src/Common/CodeLocation.h

    r3c64c668 r58fe85a  
    4242        }
    4343
    44         bool followedBy( CodeLocation const & other, int seperation ) {
     44        bool startsBefore( CodeLocation const & other ) const {
     45                if( filename < other.filename ) return true;
     46                if( filename > other.filename ) return false;
     47
     48                if( first_line < other.first_line ) return true;
     49                if( first_line > other.first_line ) return false;
     50
     51                if( last_line < other.last_line ) return true;
     52                return false;
     53        }
     54
     55        bool followedBy( CodeLocation const & other, int seperation ) const {
    4556                return (first_line + seperation == other.first_line &&
    4657                        filename == other.filename);
    4758        }
    4859
    49         bool operator==( CodeLocation const & other ) {
     60        bool operator==( CodeLocation const & other ) const {
    5061                return followedBy( other, 0 );
    5162        }
    5263
    53         bool operator!=( CodeLocation const & other ) {
     64        bool operator!=( CodeLocation const & other ) const {
    5465                return !(*this == other);
    5566        }
  • src/Common/Eval.cc

    r3c64c668 r58fe85a  
    168168        if (expr) {
    169169                expr->accept(ev);
    170                 return std::make_pair(ev.pass.value, ev.pass.valid);
     170                return std::make_pair(ev.core.value, ev.core.valid);
    171171        } else {
    172172                return std::make_pair(0, false);
  • src/Common/PassVisitor.h

    r3c64c668 r58fe85a  
    110110        virtual void visit( FinallyStmt * finallyStmt ) override final;
    111111        virtual void visit( const FinallyStmt * finallyStmt ) override final;
     112        virtual void visit( SuspendStmt * suspendStmt ) override final;
     113        virtual void visit( const SuspendStmt * suspendStmt ) override final;
    112114        virtual void visit( WaitForStmt * waitforStmt ) override final;
    113115        virtual void visit( const WaitForStmt * waitforStmt ) override final;
     
    276278        virtual Statement * mutate( CatchStmt * catchStmt ) override final;
    277279        virtual Statement * mutate( FinallyStmt * finallyStmt ) override final;
     280        virtual Statement * mutate( SuspendStmt * suspendStmt ) override final;
    278281        virtual Statement * mutate( WaitForStmt * waitforStmt ) override final;
    279282        virtual Declaration * mutate( WithStmt * withStmt ) override final;
     
    351354        virtual TypeSubstitution * mutate( TypeSubstitution * sub ) final;
    352355
     356        bool isInFunction() const {
     357                return inFunction;
     358        }
     359
    353360private:
    354361        bool inFunction = false;
     362        bool atFunctionTop = false;
    355363
    356364        template<typename pass_t> friend void acceptAll( std::list< Declaration* > &decls, PassVisitor< pass_t >& visitor );
     
    523531public:
    524532        PassVisitor<pass_type> * const visitor = nullptr;
     533
     534        bool isInFunction() const {
     535                return visitor->isInFunction();
     536        }
    525537};
    526538
  • src/Common/PassVisitor.impl.h

    r3c64c668 r58fe85a  
    532532                        indexerAddId( &func );
    533533                        maybeAccept_impl( node->type, *this );
    534                         // function body needs to have the same scope as parameters - CompoundStmt will not enter
    535                         // a new scope if inFunction is true
     534                        // First remember that we are now within a function.
    536535                        ValueGuard< bool > oldInFunction( inFunction );
    537536                        inFunction = true;
     537                        // The function body needs to have the same scope as parameters.
     538                        // A CompoundStmt will not enter a new scope if atFunctionTop is true.
     539                        ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     540                        atFunctionTop = true;
    538541                        maybeAccept_impl( node->statements, *this );
    539542                        maybeAccept_impl( node->attributes, *this );
     
    567570                        indexerAddId( &func );
    568571                        maybeAccept_impl( node->type, *this );
    569                         // function body needs to have the same scope as parameters - CompoundStmt will not enter
    570                         // a new scope if inFunction is true
     572                        // First remember that we are now within a function.
    571573                        ValueGuard< bool > oldInFunction( inFunction );
    572574                        inFunction = true;
     575                        // The function body needs to have the same scope as parameters.
     576                        // A CompoundStmt will not enter a new scope if atFunctionTop is true.
     577                        ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     578                        atFunctionTop = true;
    573579                        maybeAccept_impl( node->statements, *this );
    574580                        maybeAccept_impl( node->attributes, *this );
     
    601607                        indexerAddId( &func );
    602608                        maybeMutate_impl( node->type, *this );
    603                         // function body needs to have the same scope as parameters - CompoundStmt will not enter
    604                         // a new scope if inFunction is true
     609                        // First remember that we are now within a function.
    605610                        ValueGuard< bool > oldInFunction( inFunction );
    606611                        inFunction = true;
     612                        // The function body needs to have the same scope as parameters.
     613                        // A CompoundStmt will not enter a new scope if atFunctionTop is true.
     614                        ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     615                        atFunctionTop = true;
    607616                        maybeMutate_impl( node->statements, *this );
    608617                        maybeMutate_impl( node->attributes, *this );
     
    826835        {
    827836                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
    828                 maybeAccept_impl( node->parameters, *this );
    829837                maybeAccept_impl( node->base      , *this );
    830838        }
     
    849857        {
    850858                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
    851                 maybeAccept_impl( node->parameters, *this );
    852859                maybeAccept_impl( node->base      , *this );
    853860        }
     
    871878        {
    872879                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
    873                 maybeMutate_impl( node->parameters, *this );
    874880                maybeMutate_impl( node->base      , *this );
    875881        }
     
    895901        {
    896902                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
    897                 maybeAccept_impl( node->parameters, *this );
    898903                maybeAccept_impl( node->base      , *this );
    899904        }
     
    912917        {
    913918                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
    914                 maybeAccept_impl( node->parameters, *this );
    915919                maybeAccept_impl( node->base      , *this );
    916920        }
     
    929933        {
    930934                auto guard = makeFuncGuard( [this]() { indexerScopeEnter(); }, [this]() { indexerScopeLeave(); } );
    931                 maybeMutate_impl( node->parameters, *this );
    932935                maybeMutate_impl( node->base      , *this );
    933936        }
     
    10071010        VISIT_START( node );
    10081011        {
    1009                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    1010                 ValueGuard< bool > oldInFunction( inFunction );
    1011                 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeLeave(); } );
     1012                // Do not enter a new scope if atFunctionTop is true, don't leave one either.
     1013                ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     1014                auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
    10121015                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1013                 inFunction = false;
     1016                atFunctionTop = false;
    10141017                visitStatementList( node->kids );
    10151018        }
     
    10211024        VISIT_START( node );
    10221025        {
    1023                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    1024                 ValueGuard< bool > oldInFunction( inFunction );
    1025                 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeLeave(); } );
     1026                // Do not enter a new scope if atFunctionTop is true, don't leave one either.
     1027                ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     1028                auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
    10261029                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1027                 inFunction = false;
     1030                atFunctionTop = false;
    10281031                visitStatementList( node->kids );
    10291032        }
     
    10351038        MUTATE_START( node );
    10361039        {
    1037                 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    1038                 ValueGuard< bool > oldInFunction( inFunction );
    1039                 auto guard1 = makeFuncGuard( [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeEnter(); }, [this, &oldInFunction]() { if ( ! oldInFunction.old ) indexerScopeLeave(); } );
     1040                // Do not enter a new scope if atFunctionTop is true, don't leave one either.
     1041                ValueGuard< bool > oldAtFunctionTop( atFunctionTop );
     1042                auto guard1 = makeFuncGuard( [this, go = !atFunctionTop]() { if ( go ) indexerScopeEnter(); }, [this, go = !atFunctionTop]() { if ( go ) indexerScopeLeave(); } );
    10401043                auto guard2 = makeFuncGuard( [this]() { call_beginScope();   }, [this]() { call_endScope();     } );
    1041                 inFunction = false;
     1044                atFunctionTop = false;
    10421045                mutateStatementList( node->kids );
    10431046        }
     
    15171520
    15181521        maybeMutate_impl( node->block, *this );
     1522
     1523        MUTATE_END( Statement, node );
     1524}
     1525
     1526//--------------------------------------------------------------------------
     1527// SuspendStmt
     1528template< typename pass_type >
     1529void PassVisitor< pass_type >::visit( SuspendStmt * node ) {
     1530        VISIT_START( node );
     1531
     1532        maybeAccept_impl( node->then  , *this );
     1533
     1534        VISIT_END( node );
     1535}
     1536
     1537template< typename pass_type >
     1538void PassVisitor< pass_type >::visit( const SuspendStmt * node ) {
     1539        VISIT_START( node );
     1540
     1541        maybeAccept_impl( node->then  , *this );
     1542
     1543        VISIT_END( node );
     1544}
     1545
     1546template< typename pass_type >
     1547Statement * PassVisitor< pass_type >::mutate( SuspendStmt * node ) {
     1548        MUTATE_START( node );
     1549
     1550        maybeMutate_impl( node->then  , *this );
    15191551
    15201552        MUTATE_END( Statement, node );
  • src/Common/PassVisitor.proto.h

    r3c64c668 r58fe85a  
    3838        };
    3939
    40         std::stack< cleanup_t > cleanups;
     40        std::stack< cleanup_t, std::vector< cleanup_t > > cleanups;
    4141};
    4242
  • src/Common/ScopedMap.h

    r3c64c668 r58fe85a  
    9393
    9494                reference operator* () { return *it; }
    95                 pointer operator-> () { return it.operator->(); }
     95                pointer operator-> () const { return it.operator->(); }
    9696
    9797                iterator& operator++ () {
     
    249249
    250250        /// Gets the note at the given scope
     251        Note& getNote() { return scopes.back().note; }
     252        const Note& getNote() const { return scopes.back().note; }
    251253        Note& getNote( size_type i ) { return scopes[i].note; }
    252254        const Note& getNote( size_type i ) const { return scopes[i].note; }
  • src/Common/SemanticError.cc

    r3c64c668 r58fe85a  
    9090void SemanticErrorException::print() {
    9191        using std::to_string;
     92
     93        errors.sort([](const error & lhs, const error & rhs) -> bool {
     94                if(lhs.location.startsBefore(rhs.location)) return true;
     95                if(rhs.location.startsBefore(lhs.location)) return false;
     96
     97                return lhs.description < rhs.description;
     98        });
     99
    92100        for( auto err : errors ) {
    93101                std::cerr << ErrorHelpers::bold() << err.location << ErrorHelpers::error_str() << ErrorHelpers::reset_font() << err.description << std::endl;
  • src/Common/Stats/Heap.cc

    r3c64c668 r58fe85a  
    5353                const size_t passes_size = sizeof(passes) / sizeof(passes[0]);
    5454                size_t       passes_cnt = 1;
     55
     56                StatBlock    stacktrace_stats[100];
     57                size_t       stacktrace_stats_count = 0;
     58                bool         stacktrace_stats_enabled = true;
     59
     60                size_t       trace[1000];
     61                const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t);
     62                size_t       stacktrace_depth;
     63
     64                size_t new_stacktrace_id(const char * const name) {
     65                        stacktrace_stats[stacktrace_stats_count].name = name;
     66                        return stacktrace_stats_count++;
     67                }
     68
     69                void stacktrace_push(size_t id) {
     70                        ++stacktrace_depth;
     71                        assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc");
     72                        trace[stacktrace_depth] = id;
     73                }
     74
     75                void stacktrace_pop() {
     76                        assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty");
     77                        --stacktrace_depth;
     78                }
    5579
    5680                void newPass( const char * const name ) {
     
    116140                        for(size_t i = 0; i < passes_cnt; i++) {
    117141                                print(passes[i], nc, total_mallocs, total_frees, overall_peak);
     142                        }
     143
     144                        print('-', nct);
     145                        std::cerr << std::setw(nc) << "Trace";
     146                        std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
     147
     148                        print('-', nct);
     149                        for (size_t i = 0; i < stacktrace_stats_count; i++) {
     150                                print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak);
    118151                        }
    119152                        print('-', nct);
     
    188221                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    189222                                }
     223
     224                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     225                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     226                                }
    190227                                return __malloc( size );
    191228                        }
     
    196233                                        passes[passes_cnt - 1].frees++;
    197234                                        passes[passes_cnt - 1].n_allocs--;
     235                                }
     236                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     237                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
    198238                                }
    199239                                return __free( ptr );
     
    208248                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    209249                                }
     250                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     251                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     252                                }
    210253                                return __calloc( nelem, size );
    211254                        }
     
    218261                                        passes[passes_cnt - 1].frees++;
    219262                                } // if
     263                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     264                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     265                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
     266                                }
    220267                                return s;
    221268                        }
  • src/Common/Stats/Heap.h

    r3c64c668 r58fe85a  
    2020                void newPass( const char * const name );
    2121                void print();
     22
     23                size_t new_stacktrace_id(const char * const name);
     24                void stacktrace_push(size_t id);
     25                void stacktrace_pop();
    2226        }
    2327}
  • src/Common/Stats/Stats.cc

    r3c64c668 r58fe85a  
    3535        }
    3636
     37        namespace ResolveTime {
     38                bool enabled = false;
     39        }
     40
    3741        struct {
    3842                const char * const opt;
     
    4347                { "heap"    , Heap::enabled },
    4448                { "time"    , Time::enabled },
     49                { "resolve" , ResolveTime::enabled },
    4550        };
    4651
  • src/Common/module.mk

    r3c64c668 r58fe85a  
    1717SRC_COMMON = \
    1818      Common/Assert.cc \
     19      Common/CodeLocation.h \
     20      Common/CodeLocationTools.hpp \
     21      Common/CodeLocationTools.cpp \
     22      Common/CompilerError.h \
     23      Common/Debug.h \
     24      Common/ErrorObjects.h \
    1925      Common/Eval.cc \
     26      Common/Examine.cc \
     27      Common/Examine.h \
     28      Common/FilterCombos.h \
     29      Common/Indenter.h \
    2030      Common/PassVisitor.cc \
     31      Common/PassVisitor.h \
     32      Common/PassVisitor.impl.h \
     33      Common/PassVisitor.proto.h \
     34      Common/PersistentMap.h \
     35      Common/ScopedMap.h \
    2136      Common/SemanticError.cc \
     37      Common/SemanticError.h \
     38      Common/Stats.h \
     39      Common/Stats/Base.h \
    2240      Common/Stats/Counter.cc \
     41      Common/Stats/Counter.h \
    2342      Common/Stats/Heap.cc \
     43      Common/Stats/Heap.h \
     44      Common/Stats/ResolveTime.cc \
     45      Common/Stats/ResolveTime.h \
    2446      Common/Stats/Stats.cc \
    2547      Common/Stats/Time.cc \
    26       Common/UniqueName.cc
     48      Common/Stats/Time.h \
     49      Common/UnimplementedError.h \
     50      Common/UniqueName.cc \
     51      Common/UniqueName.h \
     52      Common/utility.h \
     53      Common/VectorMap.h
    2754
    2855SRC += $(SRC_COMMON) Common/DebugMalloc.cc
  • src/Common/utility.h

    r3c64c668 r58fe85a  
    360360        reverse_iterate_t( T & ref ) : ref(ref) {}
    361361
    362         typedef typename T::reverse_iterator iterator;
    363         iterator begin() { return ref.rbegin(); }
    364         iterator end() { return ref.rend(); }
     362        // this does NOT work on const T!!!
     363        // typedef typename T::reverse_iterator iterator;
     364        auto begin() { return ref.rbegin(); }
     365        auto end() { return ref.rend(); }
    365366};
    366367
  • src/CompilationState.cc

    r3c64c668 r58fe85a  
    1414//
    1515
     16#include "config.h"
     17
    1618int
    1719        astp = false,
     
    2729        nopreludep = false,
    2830        genproto = false,
     31        deterministic_output = false,
     32        useNewAST = CFA_USE_NEW_AST,
    2933        nomainp = false,
    3034        parsep = false,
  • src/CompilationState.h

    r3c64c668 r58fe85a  
    2828        nopreludep,
    2929        genproto,
     30        deterministic_output,
     31        useNewAST,
    3032        nomainp,
    3133        parsep,
  • src/Concurrency/Keywords.cc

    r3c64c668 r58fe85a  
    1616#include "Concurrency/Keywords.h"
    1717
    18 #include <cassert>                 // for assert
    19 #include <string>                  // for string, operator==
    20 
    21 #include "Common/PassVisitor.h"    // for PassVisitor
    22 #include "Common/SemanticError.h"  // for SemanticError
    23 #include "Common/utility.h"        // for deleteAll, map_range
    24 #include "CodeGen/OperatorTable.h" // for isConstructor
    25 #include "InitTweak/InitTweak.h"   // for getPointerBase
    26 #include "SynTree/LinkageSpec.h"   // for Cforall
    27 #include "SynTree/Constant.h"      // for Constant
    28 #include "SynTree/Declaration.h"   // for StructDecl, FunctionDecl, ObjectDecl
    29 #include "SynTree/Expression.h"    // for VariableExpr, ConstantExpr, Untype...
    30 #include "SynTree/Initializer.h"   // for SingleInit, ListInit, Initializer ...
    31 #include "SynTree/Label.h"         // for Label
    32 #include "SynTree/Statement.h"     // for CompoundStmt, DeclStmt, ExprStmt
    33 #include "SynTree/Type.h"          // for StructInstType, Type, PointerType
    34 #include "SynTree/Visitor.h"       // for Visitor, acceptAll
     18#include <cassert>                        // for assert
     19#include <string>                         // for string, operator==
     20
     21#include <iostream>
     22
     23#include "Common/Examine.h"               // for isMainFor
     24#include "Common/PassVisitor.h"           // for PassVisitor
     25#include "Common/SemanticError.h"         // for SemanticError
     26#include "Common/utility.h"               // for deleteAll, map_range
     27#include "CodeGen/OperatorTable.h"        // for isConstructor
     28#include "ControlStruct/LabelGenerator.h" // for LebelGenerator
     29#include "InitTweak/InitTweak.h"          // for getPointerBase
     30#include "SynTree/LinkageSpec.h"          // for Cforall
     31#include "SynTree/Constant.h"             // for Constant
     32#include "SynTree/Declaration.h"          // for StructDecl, FunctionDecl, ObjectDecl
     33#include "SynTree/Expression.h"           // for VariableExpr, ConstantExpr, Untype...
     34#include "SynTree/Initializer.h"          // for SingleInit, ListInit, Initializer ...
     35#include "SynTree/Label.h"                // for Label
     36#include "SynTree/Statement.h"            // for CompoundStmt, DeclStmt, ExprStmt
     37#include "SynTree/Type.h"                 // for StructInstType, Type, PointerType
     38#include "SynTree/Visitor.h"              // for Visitor, acceptAll
     39#include "Virtual/Tables.h"
    3540
    3641class Attribute;
    3742
    3843namespace Concurrency {
     44        inline static std::string getVTableName( std::string const & exception_name ) {
     45                return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
     46        }
     47
     48        // Only detects threads constructed with the keyword thread.
     49        inline static bool isThread( DeclarationWithType * decl ) {
     50                Type * baseType = decl->get_type()->stripDeclarator();
     51                StructInstType * instType = dynamic_cast<StructInstType *>( baseType );
     52                if ( nullptr == instType ) { return false; }
     53                return instType->baseStruct->is_thread();
     54        }
     55
    3956        //=============================================================================================
    4057        // Pass declarations
     
    5370          public:
    5471
    55                 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) :
    56                   type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
     72                ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name,
     73                        std::string&& getter_name, std::string&& context_error, std::string&& exception_name,
     74                        bool needs_main, AggregateDecl::Aggregate cast_target ) :
     75                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
     76                  context_error( context_error ), exception_name( exception_name ),
     77                  vtable_name( getVTableName( exception_name ) ),
     78                  needs_main( needs_main ), cast_target( cast_target ) {}
    5779
    5880                virtual ~ConcurrentSueKeyword() {}
     
    6284
    6385                void handle( StructDecl * );
     86                void addVtableForward( StructDecl * );
    6487                FunctionDecl * forwardDeclare( StructDecl * );
    6588                ObjectDecl * addField( StructDecl * );
     
    7598                const std::string getter_name;
    7699                const std::string context_error;
     100                const std::string exception_name;
     101                const std::string vtable_name;
    77102                bool needs_main;
    78103                AggregateDecl::Aggregate cast_target;
     
    80105                StructDecl   * type_decl = nullptr;
    81106                FunctionDecl * dtor_decl = nullptr;
     107                StructDecl * except_decl = nullptr;
     108                StructDecl * vtable_decl = nullptr;
    82109        };
    83110
     
    100127                        "get_thread",
    101128                        "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
     129                        "ThreadCancelled",
    102130                        true,
    103131                        AggregateDecl::Thread
     
    132160                        "get_coroutine",
    133161                        "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
     162                        "CoroutineCancelled",
    134163                        true,
    135164                        AggregateDecl::Coroutine
     
    146175                }
    147176        };
     177
     178
    148179
    149180        //-----------------------------------------------------------------------------
     
    164195                        "get_monitor",
    165196                        "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
     197                        "",
    166198                        false,
    167199                        AggregateDecl::Monitor
     
    177209                        mutateAll( translationUnit, impl );
    178210                }
     211        };
     212
     213        //-----------------------------------------------------------------------------
     214        //Handles generator type declarations :
     215        // generator MyGenerator {                   struct MyGenerator {
     216        //      int data;                                  int data;
     217        //      a_struct_t more_data;                      a_struct_t more_data;
     218        //                                =>             int __gen_next;
     219        // };                                        };
     220        //
     221        class GeneratorKeyword final : public ConcurrentSueKeyword {
     222          public:
     223
     224                GeneratorKeyword() : ConcurrentSueKeyword(
     225                        "$generator",
     226                        "__generator_state",
     227                        "get_generator",
     228                        "Unable to find builtin type $generator\n",
     229                        "",
     230                        true,
     231                        AggregateDecl::Generator
     232                )
     233                {}
     234
     235                virtual ~GeneratorKeyword() {}
     236
     237                virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); }
     238
     239                static void implement( std::list< Declaration * > & translationUnit ) {
     240                        PassVisitor< GeneratorKeyword > impl;
     241                        mutateAll( translationUnit, impl );
     242                }
     243        };
     244
     245
     246        //-----------------------------------------------------------------------------
     247        class SuspendKeyword final : public WithStmtsToAdd, public WithGuards {
     248        public:
     249                SuspendKeyword() = default;
     250                virtual ~SuspendKeyword() = default;
     251
     252                void  premutate( FunctionDecl * );
     253                DeclarationWithType * postmutate( FunctionDecl * );
     254
     255                Statement * postmutate( SuspendStmt * );
     256
     257                static void implement( std::list< Declaration * > & translationUnit ) {
     258                        PassVisitor< SuspendKeyword > impl;
     259                        mutateAll( translationUnit, impl );
     260                }
     261
     262        private:
     263                bool is_real_suspend( FunctionDecl * );
     264
     265                Statement * make_generator_suspend( SuspendStmt * );
     266                Statement * make_coroutine_suspend( SuspendStmt * );
     267
     268                struct LabelPair {
     269                        Label obj;
     270                        int   idx;
     271                };
     272
     273                LabelPair make_label() {
     274                        labels.push_back( gen.newLabel("generator") );
     275                        return { labels.back(), int(labels.size()) };
     276                }
     277
     278                DeclarationWithType * in_generator = nullptr;
     279                FunctionDecl * decl_suspend = nullptr;
     280                std::vector<Label> labels;
     281                ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator();
    179282        };
    180283
     
    195298                std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
    196299                void validate( DeclarationWithType * );
    197                 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    198                 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
     300                void addDtorStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
     301                void addStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
     302                void addThreadDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args );
    199303
    200304                static void implement( std::list< Declaration * > & translationUnit ) {
     
    207311                StructDecl* guard_decl = nullptr;
    208312                StructDecl* dtor_guard_decl = nullptr;
     313                StructDecl* thread_guard_decl = nullptr;
    209314
    210315                static std::unique_ptr< Type > generic_func;
     
    251356                CoroutineKeyword        ::implement( translationUnit );
    252357                MonitorKeyword  ::implement( translationUnit );
     358                GeneratorKeyword  ::implement( translationUnit );
     359                SuspendKeyword    ::implement( translationUnit );
    253360        }
    254361
     
    283390                        handle( decl );
    284391                }
     392                else if ( !except_decl && exception_name == decl->name && decl->body ) {
     393                        except_decl = decl;
     394                }
     395                else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
     396                        vtable_decl = decl;
     397                }
     398                // Might be able to get ride of is target.
     399                assert( is_target(decl) == (cast_target == decl->kind) );
    285400                return decl;
    286401        }
    287402
    288403        DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
    289                 if( !type_decl ) return decl;
    290                 if( !CodeGen::isDestructor( decl->name ) ) return decl;
    291 
    292                 auto params = decl->type->parameters;
    293                 if( params.size() != 1 ) return decl;
    294 
    295                 auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() );
    296                 if( !type ) return decl;
    297 
    298                 auto stype = dynamic_cast<StructInstType*>( type->base );
    299                 if( !stype ) return decl;
    300                 if( stype->baseStruct != type_decl ) return decl;
    301 
    302                 if( !dtor_decl ) dtor_decl = decl;
     404                if ( type_decl && isDestructorFor( decl, type_decl ) )
     405                        dtor_decl = decl;
     406                else if ( vtable_name.empty() )
     407                        ;
     408                else if( !decl->has_body() )
     409                        ;
     410                else if ( auto param = isMainFor( decl, cast_target ) ) {
     411                        // This should never trigger.
     412                        assert( vtable_decl );
     413                        // Should be safe because of isMainFor.
     414                        StructInstType * struct_type = static_cast<StructInstType *>(
     415                                static_cast<ReferenceType *>( param->get_type() )->base );
     416                        assert( struct_type );
     417
     418                        std::list< Expression * > poly_args = { new TypeExpr( struct_type->clone() ) };
     419                        ObjectDecl * vtable_object = Virtual::makeVtableInstance(
     420                                vtable_decl->makeInst( poly_args ), struct_type, nullptr );
     421                        declsToAddAfter.push_back( vtable_object );
     422                        declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
     423                                vtable_object, except_decl->makeInst( std::move( poly_args ) )
     424                        ) );
     425                }
     426
    303427                return decl;
    304428        }
     
    324448                if( !dtor_decl ) SemanticError( decl, context_error );
    325449
     450                addVtableForward( decl );
    326451                FunctionDecl * func = forwardDeclare( decl );
    327452                ObjectDecl * field = addField( decl );
    328453                addRoutines( field, func );
     454        }
     455
     456        void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
     457                if ( vtable_decl ) {
     458                        std::list< Expression * > poly_args = {
     459                                new TypeExpr( new StructInstType( noQualifiers, decl ) ),
     460                        };
     461                        declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
     462                                vtable_decl->makeInst( poly_args ),
     463                                except_decl->makeInst( poly_args )
     464                        ) );
     465                        declsToAddBefore.push_back( Virtual::makeVtableForward(
     466                                vtable_decl->makeInst( move( poly_args ) ) ) );
     467                // Its only an error if we want a vtable and don't have one.
     468                } else if ( ! vtable_name.empty() ) {
     469                        SemanticError( decl, context_error );
     470                }
    329471        }
    330472
     
    434576                                                new CastExpr(
    435577                                                        new VariableExpr( func->get_functionType()->get_parameters().front() ),
    436                                                         func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone()
     578                                                        func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone(),
     579                                                        false
    437580                                                )
    438581                                        )
     
    446589
    447590                declsToAddAfter.push_back( get_decl );
    448 
    449                 // get_decl->fixUniqueId();
    450         }
     591        }
     592
     593        //=============================================================================================
     594        // Suspend keyword implementation
     595        //=============================================================================================
     596        bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
     597                if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
     598                if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name
     599                if(func->type->parameters.size() != 0) return false; // Too many parameters
     600                if(func->type->returnVals.size() != 0) return false; // Too many return values
     601
     602                return true;
     603        }
     604
     605        void SuspendKeyword::premutate( FunctionDecl * func ) {
     606                GuardValue(in_generator);
     607                in_generator = nullptr;
     608
     609                // Is this the real suspend?
     610                if(is_real_suspend(func)) {
     611                        decl_suspend = decl_suspend ? decl_suspend : func;
     612                        return;
     613                }
     614
     615                // Is this the main of a generator?
     616                auto param = isMainFor( func, AggregateDecl::Aggregate::Generator );
     617                if(!param) return;
     618
     619                if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void");
     620
     621                in_generator = param;
     622                GuardValue(labels);
     623                labels.clear();
     624        }
     625
     626        DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) {
     627                if( !func->statements ) return func; // Not the actual definition, don't do anything
     628                if( !in_generator     ) return func; // Not in a generator, don't do anything
     629                if( labels.empty()    ) return func; // Generator has no states, nothing to do, could throw a warning
     630
     631                // This is a generator main, we need to add the following code to the top
     632                // static void * __generator_labels[] = {&&s0, &&s1, ...};
     633                // goto * __generator_labels[gen.__generator_state];
     634                const auto & loc = func->location;
     635
     636                const auto first_label = gen.newLabel("generator");
     637
     638                // for each label add to declaration
     639                std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) };
     640                for(const auto & label : labels) {
     641                        inits.push_back(
     642                                new SingleInit(
     643                                        new LabelAddressExpr( label )
     644                                )
     645                        );
     646                }
     647                auto init = new ListInit(std::move(inits), noDesignators, true);
     648                labels.clear();
     649
     650                // create decl
     651                auto decl = new ObjectDecl(
     652                        "__generator_labels",
     653                        Type::StorageClasses( Type::Static ),
     654                        LinkageSpec::AutoGen,
     655                        nullptr,
     656                        new ArrayType(
     657                                Type::Qualifiers(),
     658                                new PointerType(
     659                                        Type::Qualifiers(),
     660                                        new VoidType( Type::Qualifiers() )
     661                                ),
     662                                nullptr,
     663                                false, false
     664                        ),
     665                        init
     666                );
     667
     668                // create the goto
     669                assert(in_generator);
     670
     671                auto go_decl = new ObjectDecl(
     672                        "__generator_label",
     673                        noStorageClasses,
     674                        LinkageSpec::AutoGen,
     675                        nullptr,
     676                        new PointerType(
     677                                Type::Qualifiers(),
     678                                new VoidType( Type::Qualifiers() )
     679                        ),
     680                        new SingleInit(
     681                                new UntypedExpr(
     682                                        new NameExpr("?[?]"),
     683                                        {
     684                                                new NameExpr("__generator_labels"),
     685                                                new UntypedMemberExpr(
     686                                                        new NameExpr("__generator_state"),
     687                                                        new VariableExpr( in_generator )
     688                                                )
     689                                        }
     690                                )
     691                        )
     692                );
     693                go_decl->location = loc;
     694
     695                auto go = new BranchStmt(
     696                        new VariableExpr( go_decl ),
     697                        BranchStmt::Goto
     698                );
     699                go->location = loc;
     700                go->computedTarget->location = loc;
     701
     702                auto noop = new NullStmt({ first_label });
     703                noop->location = loc;
     704
     705                // wrap everything in a nice compound
     706                auto body = new CompoundStmt({
     707                        new DeclStmt( decl ),
     708                        new DeclStmt( go_decl ),
     709                        go,
     710                        noop,
     711                        func->statements
     712                });
     713                body->location   = loc;
     714                func->statements = body;
     715
     716                return func;
     717        }
     718
     719        Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) {
     720                SuspendStmt::Type type = stmt->type;
     721                if(type == SuspendStmt::None) {
     722                        // This suspend has a implicit target, find it
     723                        type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine;
     724                }
     725
     726                // Check that the target makes sense
     727                if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type.");
     728
     729                // Act appropriately
     730                switch(type) {
     731                        case SuspendStmt::Generator: return make_generator_suspend(stmt);
     732                        case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt);
     733                        default: abort();
     734                }
     735        }
     736
     737        Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) {
     738                assert(in_generator);
     739                // Target code is :
     740                //   gen.__generator_state = X;
     741                //   { THEN }
     742                //   return;
     743                //   __gen_X:;
     744
     745                // Save the location and delete the old statement, we only need the location from this point on
     746                auto loc = stmt->location;
     747
     748                // Build the label and get its index
     749                auto label = make_label();
     750
     751                // Create the context saving statement
     752                auto save = new ExprStmt( new UntypedExpr(
     753                        new NameExpr( "?=?" ),
     754                        {
     755                                new UntypedMemberExpr(
     756                                        new NameExpr("__generator_state"),
     757                                        new VariableExpr( in_generator )
     758                                ),
     759                                new ConstantExpr(
     760                                        Constant::from_int( label.idx )
     761                                )
     762                        }
     763                ));
     764                assert(save->expr);
     765                save->location = loc;
     766                stmtsToAddBefore.push_back( save );
     767
     768                // if we have a then add it here
     769                auto then = stmt->then;
     770                stmt->then = nullptr;
     771                delete stmt;
     772                if(then) stmtsToAddBefore.push_back( then );
     773
     774                // Create the return statement
     775                auto ret = new ReturnStmt( nullptr );
     776                ret->location = loc;
     777                stmtsToAddBefore.push_back( ret );
     778
     779                // Create the null statement with the created label
     780                auto noop = new NullStmt({ label.obj });
     781                noop->location = loc;
     782
     783                // Return the null statement to take the place of the previous statement
     784                return noop;
     785        }
     786
     787        Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) {
     788                if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented.");
     789
     790                // Save the location and delete the old statement, we only need the location from this point on
     791                auto loc = stmt->location;
     792                delete stmt;
     793
     794                // Create the call expression
     795                if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n");
     796                auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) );
     797                expr->location = loc;
     798
     799                // Change this statement into a regular expr
     800                assert(expr);
     801                auto nstmt = new ExprStmt( expr );
     802                nstmt->location = loc;
     803                return nstmt;
     804        }
     805
    451806
    452807        //=============================================================================================
     
    458813                bool first = false;
    459814                std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
    460                 bool isDtor = CodeGen::isDestructor( decl->name );
     815                bool const isDtor = CodeGen::isDestructor( decl->name );
    461816
    462817                // Is this function relevant to monitors
     
    506861
    507862                // Instrument the body
    508                 if( isDtor ) {
    509                         addDtorStatments( decl, body, mutexArgs );
     863                if ( isDtor && isThread( mutexArgs.front() ) ) {
     864                        if( !thread_guard_decl ) {
     865                                SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" );
     866                        }
     867                        addThreadDtorStatements( decl, body, mutexArgs );
     868                }
     869                else if ( isDtor ) {
     870                        addDtorStatements( decl, body, mutexArgs );
    510871                }
    511872                else {
    512                         addStatments( decl, body, mutexArgs );
     873                        addStatements( decl, body, mutexArgs );
    513874                }
    514875        }
     
    527888                        assert( !dtor_guard_decl );
    528889                        dtor_guard_decl = decl;
     890                }
     891                else if( decl->name == "thread_dtor_guard_t" && decl->body ) {
     892                        assert( !thread_guard_decl );
     893                        thread_guard_decl = decl;
    529894                }
    530895        }
     
    565930        }
    566931
    567         void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     932        void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    568933                Type * arg_type = args.front()->get_type()->clone();
    569934                arg_type->set_mutex( false );
     
    583948                        new SingleInit( new UntypedExpr(
    584949                                new NameExpr( "get_monitor" ),
    585                                 {  new CastExpr( new VariableExpr( args.front() ), arg_type ) }
     950                                {  new CastExpr( new VariableExpr( args.front() ), arg_type, false ) }
    586951                        ))
    587952                );
     
    604969                                        {
    605970                                                new SingleInit( new AddressExpr( new VariableExpr( monitors ) ) ),
    606                                                 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
     971                                                new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) ),
     972                                                new SingleInit( new ConstantExpr( Constant::from_bool( false ) ) )
    607973                                        },
    608974                                        noDesignators,
     
    613979
    614980                //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
    615                 body->push_front( new DeclStmt( monitors) );
    616         }
    617 
    618         void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     981                body->push_front( new DeclStmt( monitors ) );
     982        }
     983
     984        void MutexKeyword::addThreadDtorStatements(
     985                        FunctionDecl*, CompoundStmt * body,
     986                        const std::list<DeclarationWithType * > & args ) {
     987                assert( args.size() == 1 );
     988                DeclarationWithType * arg = args.front();
     989                Type * arg_type = arg->get_type()->clone();
     990                assert( arg_type->get_mutex() );
     991                arg_type->set_mutex( false );
     992
     993                // thread_dtor_guard_t __guard = { this, intptr( 0 ) };
     994                body->push_front(
     995                        new DeclStmt( new ObjectDecl(
     996                                "__guard",
     997                                noStorageClasses,
     998                                LinkageSpec::Cforall,
     999                                nullptr,
     1000                                new StructInstType(
     1001                                        noQualifiers,
     1002                                        thread_guard_decl
     1003                                ),
     1004                                new ListInit(
     1005                                        {
     1006                                                new SingleInit( new CastExpr( new VariableExpr( arg ), arg_type ) ),
     1007                                                new SingleInit( new UntypedExpr(
     1008                                                        new NameExpr( "intptr" ), {
     1009                                                                new ConstantExpr( Constant::from_int( 0 ) ),
     1010                                                        }
     1011                                                ) ),
     1012                                        },
     1013                                        noDesignators,
     1014                                        true
     1015                                )
     1016                        ))
     1017                );
     1018        }
     1019
     1020        void MutexKeyword::addStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
    6191021                ObjectDecl * monitors = new ObjectDecl(
    6201022                        "__monitors",
     
    6411043                                        return new SingleInit( new UntypedExpr(
    6421044                                                new NameExpr( "get_monitor" ),
    643                                                 {  new CastExpr( new VariableExpr( var ), type ) }
     1045                                                {  new CastExpr( new VariableExpr( var ), type, false ) }
    6441046                                        ) );
    6451047                                })
     
    6651067                                                new SingleInit( new VariableExpr( monitors ) ),
    6661068                                                new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ),
    667                                                 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
     1069                                                new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) )
    6681070                                        },
    6691071                                        noDesignators,
     
    7271129// tab-width: 4 //
    7281130// End: //
     1131
  • src/Concurrency/Waitfor.cc

    r3c64c668 r58fe85a  
    384384                                                                decl_monitor
    385385                                                        )
    386                                                 )
     386                                                ),
     387                                                false
    387388                                        );
    388389
     
    408409                        new CompoundStmt({
    409410                                makeAccStatement( acceptables, index, "is_dtor", detectIsDtor( clause.target.function )                                    , indexer ),
    410                                 makeAccStatement( acceptables, index, "func"   , new CastExpr( clause.target.function, fptr_t )                            , indexer ),
     411                                makeAccStatement( acceptables, index, "func"   , new CastExpr( clause.target.function, fptr_t, false )                     , indexer ),
    411412                                makeAccStatement( acceptables, index, "data"   , new VariableExpr( monitors )                                              , indexer ),
    412413                                makeAccStatement( acceptables, index, "size"   , new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ), indexer ),
     
    531532                                                                decl_mask
    532533                                                        )
    533                                                 )
     534                                                ),
     535                                                false
    534536                                        ),
    535537                                        timeout
  • src/Concurrency/module.mk

    r3c64c668 r58fe85a  
    1515###############################################################################
    1616
    17 SRC += Concurrency/Keywords.cc Concurrency/Waitfor.cc
     17SRC += Concurrency/Keywords.cc Concurrency/Keywords.h Concurrency/Waitfor.cc Concurrency/Waitfor.h
    1818SRCDEMANGLE += Concurrency/Keywords.cc
    1919
  • src/ControlStruct/ExceptTranslate.cc

    r3c64c668 r58fe85a  
    99// Author           : Andrew Beach
    1010// Created On       : Wed Jun 14 16:49:00 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:40:15 2019
    13 // Update Count     : 12
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jun 24 11:18:00 2020
     13// Update Count     : 17
    1414//
    1515
     
    6464        }
    6565
    66         class ExceptionMutatorCore : public WithGuards {
    67                 enum Context { NoHandler, TerHandler, ResHandler };
    68 
    69                 // Also need to handle goto, break & continue.
    70                 // They need to be cut off in a ResHandler, until we enter another
    71                 // loop, switch or the goto stays within the function.
    72 
    73                 Context cur_context;
    74 
    75                 // The current (innermost) termination handler exception declaration.
    76                 ObjectDecl * handler_except_decl;
    77 
     66        class ThrowMutatorCore : public WithGuards {
     67                ObjectDecl * terminate_handler_except;
     68                enum Context { NoHandler, TerHandler, ResHandler } cur_context;
     69
     70                // The helper functions for code/syntree generation.
     71                Statement * create_either_throw(
     72                        ThrowStmt * throwStmt, const char * throwFunc );
     73                Statement * create_terminate_rethrow( ThrowStmt * throwStmt );
     74
     75        public:
     76                ThrowMutatorCore() :
     77                        terminate_handler_except( nullptr ),
     78                        cur_context( NoHandler )
     79                {}
     80
     81                void premutate( CatchStmt *catchStmt );
     82                Statement * postmutate( ThrowStmt *throwStmt );
     83        };
     84
     85        // ThrowStmt Mutation Helpers
     86
     87        Statement * ThrowMutatorCore::create_either_throw(
     88                        ThrowStmt * throwStmt, const char * throwFunc ) {
     89                // `throwFunc`( `throwStmt->get_name()` );
     90                UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );
     91                call->get_args().push_back( throwStmt->get_expr() );
     92                throwStmt->set_expr( nullptr );
     93                delete throwStmt;
     94                return new ExprStmt( call );
     95        }
     96
     97        Statement * ThrowMutatorCore::create_terminate_rethrow(
     98                        ThrowStmt *throwStmt ) {
     99                // { `terminate_handler_except` = 0p; __rethrow_terminate(); }
     100                assert( nullptr == throwStmt->get_expr() );
     101                assert( terminate_handler_except );
     102
     103                CompoundStmt * result = new CompoundStmt();
     104                result->labels =  throwStmt->labels;
     105                result->push_back( new ExprStmt( UntypedExpr::createAssign(
     106                        nameOf( terminate_handler_except ),
     107                        new ConstantExpr( Constant::null(
     108                                terminate_handler_except->get_type()->clone()
     109                                ) )
     110                        ) ) );
     111                result->push_back( new ExprStmt(
     112                        new UntypedExpr( new NameExpr( "__cfaehm_rethrow_terminate" ) )
     113                        ) );
     114                delete throwStmt;
     115                return result;
     116        }
     117
     118        // Visiting/Mutating Functions
     119
     120        void ThrowMutatorCore::premutate( CatchStmt *catchStmt ) {
     121                // Validate the statement's form.
     122                ObjectDecl * decl = dynamic_cast<ObjectDecl *>( catchStmt->get_decl() );
     123                // Also checking the type would be nice.
     124                if ( !decl || !dynamic_cast<PointerType *>( decl->type ) ) {
     125                        std::string kind = (CatchStmt::Terminate == catchStmt->kind) ? "catch" : "catchResume";
     126                        SemanticError( catchStmt->location, kind + " must have pointer to an exception type" );
     127                }
     128
     129                // Track the handler context.
     130                GuardValue( cur_context );
     131                if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
     132                        cur_context = TerHandler;
     133
     134                        GuardValue( terminate_handler_except );
     135                        terminate_handler_except = decl;
     136                } else {
     137                        cur_context = ResHandler;
     138                }
     139        }
     140
     141        Statement * ThrowMutatorCore::postmutate( ThrowStmt *throwStmt ) {
     142                // Ignoring throwStmt->get_target() for now.
     143                if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
     144                        if ( throwStmt->get_expr() ) {
     145                                return create_either_throw( throwStmt, "$throw" );
     146                        } else if ( TerHandler == cur_context ) {
     147                                return create_terminate_rethrow( throwStmt );
     148                        } else {
     149                                abort("Invalid throw in %s at %i\n",
     150                                        throwStmt->location.filename.c_str(),
     151                                        throwStmt->location.first_line);
     152                        }
     153                } else {
     154                        if ( throwStmt->get_expr() ) {
     155                                return create_either_throw( throwStmt, "$throwResume" );
     156                        } else if ( ResHandler == cur_context ) {
     157                                // This has to be handled later.
     158                                return throwStmt;
     159                        } else {
     160                                abort("Invalid throwResume in %s at %i\n",
     161                                        throwStmt->location.filename.c_str(),
     162                                        throwStmt->location.first_line);
     163                        }
     164                }
     165        }
     166
     167        class TryMutatorCore {
    78168                // The built in types used in translation.
    79169                StructDecl * except_decl;
     
    82172
    83173                // The many helper functions for code/syntree generation.
    84                 Statement * create_given_throw(
    85                         const char * throwFunc, ThrowStmt * throwStmt );
    86                 Statement * create_terminate_throw( ThrowStmt * throwStmt );
    87                 Statement * create_terminate_rethrow( ThrowStmt * throwStmt );
    88                 Statement * create_resume_throw( ThrowStmt * throwStmt );
    89                 Statement * create_resume_rethrow( ThrowStmt * throwStmt );
    90174                CompoundStmt * take_try_block( TryStmt * tryStmt );
    91175                FunctionDecl * create_try_wrapper( CompoundStmt * body );
     
    101185                FunctionDecl * create_finally_wrapper( TryStmt * tryStmt );
    102186                ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper );
     187                Statement * create_resume_rethrow( ThrowStmt * throwStmt );
    103188
    104189                // Types used in translation, make sure to use clone.
     
    121206
    122207        public:
    123                 ExceptionMutatorCore() :
    124                         cur_context( NoHandler ),
    125                         handler_except_decl( nullptr ),
     208                TryMutatorCore() :
    126209                        except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr ),
    127210                        try_func_t( noQualifiers, false ),
     
    132215                {}
    133216
    134                 void premutate( CatchStmt *catchStmt );
    135217                void premutate( StructDecl *structDecl );
     218                Statement * postmutate( TryStmt *tryStmt );
    136219                Statement * postmutate( ThrowStmt *throwStmt );
    137                 Statement * postmutate( TryStmt *tryStmt );
    138220        };
    139221
    140         void ExceptionMutatorCore::init_func_types() {
     222        void TryMutatorCore::init_func_types() {
    141223                assert( except_decl );
    142224
     
    196278        }
    197279
    198         // ThrowStmt Mutation Helpers
    199 
    200         Statement * ExceptionMutatorCore::create_given_throw(
    201                         const char * throwFunc, ThrowStmt * throwStmt ) {
    202                 // `throwFunc`( `throwStmt->get_name` );
    203                 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );
    204                 call->get_args().push_back( throwStmt->get_expr() );
    205                 throwStmt->set_expr( nullptr );
    206                 delete throwStmt;
    207                 return new ExprStmt( call );
    208         }
    209 
    210         Statement * ExceptionMutatorCore::create_terminate_throw(
    211                         ThrowStmt *throwStmt ) {
    212                 // __throw_terminate( `throwStmt->get_name()` ); }
    213                 return create_given_throw( "__cfaabi_ehm__throw_terminate", throwStmt );
    214         }
    215 
    216         Statement * ExceptionMutatorCore::create_terminate_rethrow(
    217                         ThrowStmt *throwStmt ) {
    218                 // { `handler_except_decl` = NULL; __rethrow_terminate(); }
    219                 assert( nullptr == throwStmt->get_expr() );
    220                 assert( handler_except_decl );
    221 
    222                 CompoundStmt * result = new CompoundStmt();
    223                 result->labels =  throwStmt->labels;
    224                 result->push_back( new ExprStmt( UntypedExpr::createAssign(
    225                         nameOf( handler_except_decl ),
    226                         new ConstantExpr( Constant::null(
    227                                 new PointerType(
    228                                         noQualifiers,
    229                                         handler_except_decl->get_type()->clone()
    230                                         )
    231                                 ) )
    232                         ) ) );
    233                 result->push_back( new ExprStmt(
    234                         new UntypedExpr( new NameExpr( "__cfaabi_ehm__rethrow_terminate" ) )
    235                         ) );
    236                 delete throwStmt;
    237                 return result;
    238         }
    239 
    240         Statement * ExceptionMutatorCore::create_resume_throw(
    241                         ThrowStmt *throwStmt ) {
    242                 // __throw_resume( `throwStmt->get_name` );
    243                 return create_given_throw( "__cfaabi_ehm__throw_resume", throwStmt );
    244         }
    245 
    246         Statement * ExceptionMutatorCore::create_resume_rethrow(
    247                         ThrowStmt *throwStmt ) {
    248                 // return false;
    249                 Statement * result = new ReturnStmt(
    250                         new ConstantExpr( Constant::from_bool( false ) )
    251                         );
    252                 result->labels = throwStmt->labels;
    253                 delete throwStmt;
    254                 return result;
    255         }
    256 
    257280        // TryStmt Mutation Helpers
    258281
    259         CompoundStmt * ExceptionMutatorCore::take_try_block( TryStmt *tryStmt ) {
     282        CompoundStmt * TryMutatorCore::take_try_block( TryStmt *tryStmt ) {
    260283                CompoundStmt * block = tryStmt->get_block();
    261284                tryStmt->set_block( nullptr );
     
    263286        }
    264287
    265         FunctionDecl * ExceptionMutatorCore::create_try_wrapper(
     288        FunctionDecl * TryMutatorCore::create_try_wrapper(
    266289                        CompoundStmt *body ) {
    267290
     
    270293        }
    271294
    272         FunctionDecl * ExceptionMutatorCore::create_terminate_catch(
     295        FunctionDecl * TryMutatorCore::create_terminate_catch(
    273296                        CatchList &handlers ) {
    274297                std::list<CaseStmt *> handler_wrappers;
     
    309332                        local_except->get_attributes().push_back( new Attribute(
    310333                                "cleanup",
    311                                 { new NameExpr( "__cfaabi_ehm__cleanup_terminate" ) }
     334                                { new NameExpr( "__cfaehm_cleanup_terminate" ) }
    312335                                ) );
    313336
     
    350373        // Create a single check from a moddified handler.
    351374        // except_obj is referenced, modded_handler will be freed.
    352         CompoundStmt * ExceptionMutatorCore::create_single_matcher(
     375        CompoundStmt * TryMutatorCore::create_single_matcher(
    353376                        DeclarationWithType * except_obj, CatchStmt * modded_handler ) {
    354377                // {
     
    388411        }
    389412
    390         FunctionDecl * ExceptionMutatorCore::create_terminate_match(
     413        FunctionDecl * TryMutatorCore::create_terminate_match(
    391414                        CatchList &handlers ) {
    392415                // int match(exception * except) {
     
    425448        }
    426449
    427         CompoundStmt * ExceptionMutatorCore::create_terminate_caller(
     450        CompoundStmt * TryMutatorCore::create_terminate_caller(
    428451                        FunctionDecl * try_wrapper,
    429452                        FunctionDecl * terminate_catch,
    430453                        FunctionDecl * terminate_match ) {
    431                 // { __cfaabi_ehm__try_terminate(`try`, `catch`, `match`); }
     454                // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
    432455
    433456                UntypedExpr * caller = new UntypedExpr( new NameExpr(
    434                         "__cfaabi_ehm__try_terminate" ) );
     457                        "__cfaehm_try_terminate" ) );
    435458                std::list<Expression *>& args = caller->get_args();
    436459                args.push_back( nameOf( try_wrapper ) );
     
    443466        }
    444467
    445         FunctionDecl * ExceptionMutatorCore::create_resume_handler(
     468        FunctionDecl * TryMutatorCore::create_resume_handler(
    446469                        CatchList &handlers ) {
    447470                // bool handle(exception * except) {
     
    480503        }
    481504
    482         CompoundStmt * ExceptionMutatorCore::create_resume_wrapper(
     505        CompoundStmt * TryMutatorCore::create_resume_wrapper(
    483506                        Statement * wraps,
    484507                        FunctionDecl * resume_handler ) {
     
    486509
    487510                // struct __try_resume_node __resume_node
    488                 //      __attribute__((cleanup( __cfaabi_ehm__try_resume_cleanup )));
     511                //      __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
    489512                // ** unwinding of the stack here could cause problems **
    490513                // ** however I don't think that can happen currently **
    491                 // __cfaabi_ehm__try_resume_setup( &__resume_node, resume_handler );
     514                // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
    492515
    493516                std::list< Attribute * > attributes;
     
    495518                        std::list< Expression * > attr_params;
    496519                        attr_params.push_back( new NameExpr(
    497                                 "__cfaabi_ehm__try_resume_cleanup" ) );
     520                                "__cfaehm_try_resume_cleanup" ) );
    498521                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
    499522                }
     
    514537
    515538                UntypedExpr *setup = new UntypedExpr( new NameExpr(
    516                         "__cfaabi_ehm__try_resume_setup" ) );
     539                        "__cfaehm_try_resume_setup" ) );
    517540                setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) );
    518541                setup->get_args().push_back( nameOf( resume_handler ) );
     
    524547        }
    525548
    526         FunctionDecl * ExceptionMutatorCore::create_finally_wrapper(
     549        FunctionDecl * TryMutatorCore::create_finally_wrapper(
    527550                        TryStmt * tryStmt ) {
    528                 // void finally() { <finally code> }
     551                // void finally() { `finally->block` }
    529552                FinallyStmt * finally = tryStmt->get_finally();
    530553                CompoundStmt * body = finally->get_block();
     
    537560        }
    538561
    539         ObjectDecl * ExceptionMutatorCore::create_finally_hook(
     562        ObjectDecl * TryMutatorCore::create_finally_hook(
    540563                        FunctionDecl * finally_wrapper ) {
    541                 // struct __cfaabi_ehm__cleanup_hook __finally_hook
    542                 //      __attribute__((cleanup( finally_wrapper )));
     564                // struct __cfaehm_cleanup_hook __finally_hook
     565                //      __attribute__((cleanup( `finally_wrapper` )));
    543566
    544567                // Make Cleanup Attribute.
     
    564587        }
    565588
     589        Statement * TryMutatorCore::create_resume_rethrow( ThrowStmt *throwStmt ) {
     590                // return false;
     591                Statement * result = new ReturnStmt(
     592                        new ConstantExpr( Constant::from_bool( false ) )
     593                        );
     594                result->labels = throwStmt->labels;
     595                delete throwStmt;
     596                return result;
     597        }
     598
    566599        // Visiting/Mutating Functions
    567         void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) {
    568                 // Validate the Statement's form.
    569                 ObjectDecl * decl =
    570                         dynamic_cast<ObjectDecl *>( catchStmt->get_decl() );
    571                 if ( decl && true /* check decl->get_type() */ ) {
    572                         // Pass.
    573                 } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
    574                         SemanticError(catchStmt->location, "catch must have exception type");
    575                 } else {
    576                         SemanticError(catchStmt->location, "catchResume must have exception type");
    577                 }
    578 
    579                 // Track the handler context.
    580                 GuardValue( cur_context );
    581                 if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
    582                         cur_context = TerHandler;
    583 
    584                         GuardValue( handler_except_decl );
    585                         handler_except_decl = decl;
    586                 } else {
    587                         cur_context = ResHandler;
    588                 }
    589         }
    590 
    591         void ExceptionMutatorCore::premutate( StructDecl *structDecl ) {
     600        void TryMutatorCore::premutate( StructDecl *structDecl ) {
    592601                if ( !structDecl->has_body() ) {
    593602                        // Skip children?
    594603                        return;
    595                 } else if ( structDecl->get_name() == "__cfaabi_ehm__base_exception_t" ) {
     604                } else if ( structDecl->get_name() == "__cfaehm_base_exception_t" ) {
    596605                        assert( nullptr == except_decl );
    597606                        except_decl = structDecl;
    598607                        init_func_types();
    599                 } else if ( structDecl->get_name() == "__cfaabi_ehm__try_resume_node" ) {
     608                } else if ( structDecl->get_name() == "__cfaehm_try_resume_node" ) {
    600609                        assert( nullptr == node_decl );
    601610                        node_decl = structDecl;
    602                 } else if ( structDecl->get_name() == "__cfaabi_ehm__cleanup_hook" ) {
     611                } else if ( structDecl->get_name() == "__cfaehm_cleanup_hook" ) {
    603612                        assert( nullptr == hook_decl );
    604613                        hook_decl = structDecl;
    605614                }
    606                 // Later we might get the exception type as well.
    607         }
    608 
    609         Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) {
    610                 assert( except_decl );
    611 
    612                 // Ignoring throwStmt->get_target() for now.
    613                 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
    614                         if ( throwStmt->get_expr() ) {
    615                                 return create_terminate_throw( throwStmt );
    616                         } else if ( TerHandler == cur_context ) {
    617                                 return create_terminate_rethrow( throwStmt );
    618                         } else {
    619                                 abort("Invalid throw in %s at %i\n",
    620                                         throwStmt->location.filename.c_str(),
    621                                         throwStmt->location.first_line);
    622                         }
    623                 } else {
    624                         if ( throwStmt->get_expr() ) {
    625                                 return create_resume_throw( throwStmt );
    626                         } else if ( ResHandler == cur_context ) {
    627                                 return create_resume_rethrow( throwStmt );
    628                         } else {
    629                                 abort("Invalid throwResume in %s at %i\n",
    630                                         throwStmt->location.filename.c_str(),
    631                                         throwStmt->location.first_line);
    632                         }
    633                 }
    634         }
    635 
    636         Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) {
     615        }
     616
     617        Statement * TryMutatorCore::postmutate( TryStmt *tryStmt ) {
    637618                assert( except_decl );
    638619                assert( node_decl );
     
    688669        }
    689670
    690         void translateEHM( std::list< Declaration *> & translationUnit ) {
    691                 PassVisitor<ExceptionMutatorCore> translator;
     671        Statement * TryMutatorCore::postmutate( ThrowStmt *throwStmt ) {
     672                // Only valid `throwResume;` statements should remain. (2/3 checks)
     673                assert( ThrowStmt::Resume == throwStmt->kind && ! throwStmt->expr );
     674                return create_resume_rethrow( throwStmt );
     675        }
     676
     677        void translateThrows( std::list< Declaration *> & translationUnit ) {
     678                PassVisitor<ThrowMutatorCore> translator;
    692679                mutateAll( translationUnit, translator );
    693680        }
     681
     682        void translateTries( std::list< Declaration *> & translationUnit ) {
     683                PassVisitor<TryMutatorCore> translator;
     684                mutateAll( translationUnit, translator );
     685        }
    694686}
  • src/ControlStruct/ExceptTranslate.h

    r3c64c668 r58fe85a  
    99// Author           : Andrew Beach
    1010// Created On       : Tus Jun 06 10:13:00 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:19:23 2017
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tus May 19 11:47:00 2020
     13// Update Count     : 5
    1414//
    1515
     
    2121
    2222namespace ControlStruct {
    23         void translateEHM( std::list< Declaration *> & translationUnit );
    24         // Converts exception handling structures into their underlying C code.  Translation does use the exception
    25         // handling header, make sure it is visible wherever translation occurs.
     23        void translateThrows( std::list< Declaration *> & translationUnit );
     24        /* Replaces all throw & throwResume statements with function calls.
     25         * These still need to be resolved, so call this before the reslover.
     26         */
     27
     28        void translateTries( std::list< Declaration *> & translationUnit );
     29        /* Replaces all try blocks (and their many clauses) with function definitions and calls.
     30         * This uses the exception built-ins to produce typed output and should take place after
     31         * the resolver. It also produces virtual casts and should happen before they are expanded.
     32         */
    2633}
    2734
  • src/ControlStruct/module.mk

    r3c64c668 r58fe85a  
    1717SRC_CONTROLSTRUCT = \
    1818        ControlStruct/ForExprMutator.cc \
     19        ControlStruct/ForExprMutator.h \
    1920        ControlStruct/LabelFixer.cc \
     21        ControlStruct/LabelFixer.h \
    2022        ControlStruct/LabelGenerator.cc \
     23        ControlStruct/LabelGenerator.h \
    2124        ControlStruct/MLEMutator.cc \
    22         ControlStruct/Mutate.cc
     25        ControlStruct/MLEMutator.h \
     26        ControlStruct/Mutate.cc \
     27        ControlStruct/Mutate.h
    2328
    24 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc
     29SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc ControlStruct/ExceptTranslate.h
    2530SRCDEMANGLE += $(SRC_CONTROLSTRUCT)
    2631
  • src/GenPoly/GenPoly.cc

    r3c64c668 r58fe85a  
    4646                }
    4747
     48                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) {
     49                        for (auto &param : params) {
     50                                auto paramType = param.strict_as<ast::TypeExpr>();
     51                                if (isPolyType(paramType->type, env)) return true;
     52                        }
     53                        return false;
     54                }
     55
    4856                /// Checks a parameter list for polymorphic parameters from tyVars; will substitute according to env if present
    4957                bool hasPolyParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
     
    5664                }
    5765
     66                bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
     67                        for (auto &param : params) {
     68                                auto paramType = param.strict_as<ast::TypeExpr>();
     69                                if (isPolyType(paramType->type, tyVars, env)) return true;
     70                        }
     71                        return false;
     72                }
     73
    5874                /// Checks a parameter list for dynamic-layout parameters from tyVars; will substitute according to env if present
    5975                bool hasDynParams( std::list< Expression* >& params, const TyVarMap &tyVars, const TypeSubstitution *env ) {
     
    92108                        Type *newType = env->lookup( typeInst->get_name() );
    93109                        if ( newType ) return newType;
     110                }
     111                return type;
     112        }
     113
     114        const ast::Type * replaceTypeInst(const ast::Type * type, const ast::TypeSubstitution * env) {
     115                if (!env) return type;
     116                if (auto typeInst = dynamic_cast<const ast::TypeInstType*> (type)) {
     117                        auto newType = env->lookup(typeInst);
     118                        if (newType) return newType;
    94119                }
    95120                return type;
     
    111136        }
    112137
     138        const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env) {
     139                type = replaceTypeInst( type, env );
     140
     141                if ( dynamic_cast< const ast::TypeInstType * >( type ) ) {
     142                        return type;
     143                } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
     144                        return isPolyType( arrayType->base, env );
     145                } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) {
     146                        if ( hasPolyParams( structType->params, env ) ) return type;
     147                } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) {
     148                        if ( hasPolyParams( unionType->params, env ) ) return type;
     149                }
     150                return 0;
     151        }
     152
    113153        Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
    114154                type = replaceTypeInst( type, env );
     
    126166                }
    127167                return 0;
     168        }
     169
     170        const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
     171                type = replaceTypeInst( type, env );
     172
     173                if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
     174                        return tyVars.find(typeInst->typeString()) != tyVars.end() ? type : nullptr;
     175                } else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
     176                        return isPolyType( arrayType->base, env );
     177                } else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) {
     178                        if ( hasPolyParams( structType->params, env ) ) return type;
     179                } else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) {
     180                        if ( hasPolyParams( unionType->params, env ) ) return type;
     181                }
     182                return nullptr;
    128183        }
    129184
     
    449504        }
    450505
     506        namespace {
     507                // temporary hack to avoid re-implementing anything related to TyVarMap
     508                // does this work? these two structs have identical definitions.
     509                inline TypeDecl::Data convData(const ast::TypeDecl::Data & data) {
     510                        return *reinterpret_cast<const TypeDecl::Data *>(&data);
     511                }
     512        }
     513
    451514        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env ) {
    452515                // is parameter is not polymorphic, don't need to box
     
    459522        }
    460523
     524        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env) {
     525                // is parameter is not polymorphic, don't need to box
     526                if ( ! isPolyType( param, exprTyVars ) ) return false;
     527                ast::ptr<ast::Type> newType = arg;
     528                if ( env ) env->apply( newType );
     529                // if the argument's type is polymorphic, we don't need to box again!
     530                return ! isPolyType( newType );
     531        }
     532
    461533        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env ) {
    462534                FunctionType * function = getFunctionType( appExpr->function->result );
     
    467539        }
    468540
     541        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env) {
     542                const ast::FunctionType * function = getFunctionType(appExpr->func->result);
     543                assertf( function, "ApplicationExpr has non-function type: %s", toString( appExpr->func->result ).c_str() );
     544                TyVarMap exprTyVars(TypeDecl::Data{});
     545                makeTyVarMap(function, exprTyVars);
     546                return needsBoxing(param, arg, exprTyVars, env);
     547
     548        }
     549
    469550        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
    470551                tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );
     552        }
     553
     554        void addToTyVarMap( const ast::TypeInstType * tyVar, TyVarMap & tyVarMap) {
     555                tyVarMap.insert(tyVar->typeString(), convData(ast::TypeDecl::Data{tyVar->base}));
    471556        }
    472557
     
    478563                if ( PointerType *pointer = dynamic_cast< PointerType* >( type ) ) {
    479564                        makeTyVarMap( pointer->get_base(), tyVarMap );
     565                }
     566        }
     567
     568        void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap) {
     569                if (auto ptype = dynamic_cast<const ast::FunctionType *>(type)) {
     570                        for (auto & tyVar : ptype->forall) {
     571                                assert (tyVar);
     572                                addToTyVarMap(tyVar, tyVarMap);
     573                        }
     574                }
     575                if (auto pointer = dynamic_cast<const ast::PointerType *>(type)) {
     576                        makeTyVarMap(pointer->base, tyVarMap);
    480577                }
    481578        }
  • src/GenPoly/GenPoly.h

    r3c64c668 r58fe85a  
    2626
    2727namespace GenPoly {
     28
    2829        typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
    29 
    3030        /// Replaces a TypeInstType by its referrent in the environment, if applicable
    3131        Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
     
    3333        /// returns polymorphic type if is polymorphic type, NULL otherwise; will look up substitution in env if provided
    3434        Type *isPolyType( Type *type, const TypeSubstitution *env = 0 );
     35        const ast::Type * isPolyType(const ast::Type * type, const ast::TypeSubstitution * env = nullptr);
    3536
    3637        /// returns polymorphic type if is polymorphic type in tyVars, NULL otherwise; will look up substitution in env if provided
    3738        Type *isPolyType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
     39        const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env = nullptr);
    3840
    3941        /// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
     
    8486        /// true if arg requires boxing given exprTyVars
    8587        bool needsBoxing( Type * param, Type * arg, const TyVarMap &exprTyVars, const TypeSubstitution * env );
     88        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const TyVarMap &exprTyVars, const ast::TypeSubstitution * env);
    8689
    8790        /// true if arg requires boxing in the call to appExpr
    8891        bool needsBoxing( Type * param, Type * arg, ApplicationExpr * appExpr, const TypeSubstitution * env );
     92        bool needsBoxing( const ast::Type * param, const ast::Type * arg, const ast::ApplicationExpr * appExpr, const ast::TypeSubstitution * env);
    8993
    9094        /// Adds the type variable `tyVar` to `tyVarMap`
     
    9397        /// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
    9498        void makeTyVarMap( Type *type, TyVarMap &tyVarMap );
     99        void makeTyVarMap(const ast::Type * type, TyVarMap & tyVarMap);
    95100
    96101        /// Prints type variable map
  • src/GenPoly/InstantiateGeneric.cc

    r3c64c668 r58fe85a  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu Aug 04 18:33:00 2016
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Thu Aug 04 18:33:00 2016
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jul 16 10:17:00 2020
     13// Update Count     : 2
    1414//
    1515#include "InstantiateGeneric.h"
     
    172172                InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
    173173                /// Set of types which are dtype-only generic (and therefore have static layout)
    174                 ScopedSet< AggregateDecl* > dtypeStatics;
     174                std::set<AggregateDecl *> dtypeStatics;
    175175                /// Namer for concrete types
    176176                UniqueName typeNamer;
     
    297297        }
    298298
     299        template< typename AggrInst >
     300        static AggrInst * asForward( AggrInst * decl ) {
     301                if ( !decl->body ) {
     302                        return nullptr;
     303                }
     304                decl = decl->clone();
     305                decl->body = false;
     306                deleteAll( decl->members );
     307                decl->members.clear();
     308                return decl;
     309        }
     310
    299311        void GenericInstantiator::stripDtypeParams( AggregateDecl *base, std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs ) {
    300312                substituteMembers( base->get_members(), baseParams, typeSubs );
     
    373385                                concDecl->set_body( inst->get_baseStruct()->has_body() );
    374386                                substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
    375                                 insert( inst, typeSubs, concDecl ); // must insert before recursion
     387                                // Forward declare before recursion. (TODO: Only when needed, #199.)
     388                                insert( inst, typeSubs, concDecl );
     389                                if ( StructDecl *forwardDecl = asForward( concDecl ) ) {
     390                                        declsToAddBefore.push_back( forwardDecl );
     391                                }
    376392                                concDecl->acceptMutator( *visitor ); // recursively instantiate members
    377393                                declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first
     
    423439                                concDecl->set_body( inst->get_baseUnion()->has_body() );
    424440                                substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
    425                                 insert( inst, typeSubs, concDecl ); // must insert before recursion
     441                                // Forward declare before recursion. (TODO: Only when needed, #199.)
     442                                insert( inst, typeSubs, concDecl );
     443                                if ( UnionDecl *forwardDecl = asForward( concDecl ) ) {
     444                                        declsToAddBefore.push_back( forwardDecl );
     445                                }
    426446                                concDecl->acceptMutator( *visitor ); // recursively instantiate members
    427447                                declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first
     
    485505        void GenericInstantiator::beginScope() {
    486506                instantiations.beginScope();
    487                 dtypeStatics.beginScope();
    488507        }
    489508
    490509        void GenericInstantiator::endScope() {
    491510                instantiations.endScope();
    492                 dtypeStatics.endScope();
    493511        }
    494512
  • src/GenPoly/Specialize.cc

    r3c64c668 r58fe85a  
    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 Dec 13 23:40:49 2019
    13 // Update Count     : 32
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Jul  2 17:42:00 2020
     13// Update Count     : 33
    1414//
    1515
     
    4242
    4343namespace GenPoly {
    44         struct Specialize final : public WithConstTypeSubstitution, public WithStmtsToAdd, public WithVisitorRef<Specialize> {
     44        struct Specialize final : public WithConstTypeSubstitution,
     45                        public WithDeclsToAdd, public WithVisitorRef<Specialize> {
    4546                Expression * postmutate( ApplicationExpr *applicationExpr );
    4647                Expression * postmutate( CastExpr *castExpr );
     
    217218                thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );
    218219
     220                // Thunks at the global level must be static to avoid collisions between files.
     221                // (Conversly thunks inside a function must be unique and not static.)
     222                thunkFunc->storageClasses.is_static = !isInFunction();
     223
    219224                // thread thunk parameters into call to actual function, naming thunk parameters as we go
    220225                UniqueName paramNamer( paramPrefix );
     
    248253                } // if
    249254
    250                 // handle any specializations that may still be present
    251                 std::string oldParamPrefix = paramPrefix;
    252                 paramPrefix += "p";
    253                 // save stmtsToAddBefore in oldStmts
    254                 std::list< Statement* > oldStmts;
    255                 oldStmts.splice( oldStmts.end(), stmtsToAddBefore );
    256                 appExpr->acceptMutator( *visitor );
    257                 paramPrefix = oldParamPrefix;
    258                 // write any statements added for recursive specializations into the thunk body
    259                 thunkFunc->statements->kids.splice( thunkFunc->statements->kids.end(), stmtsToAddBefore );
    260                 // restore oldStmts into stmtsToAddBefore
    261                 stmtsToAddBefore.splice( stmtsToAddBefore.end(), oldStmts );
     255                // Handle any specializations that may still be present.
     256                {
     257                        std::string oldParamPrefix = paramPrefix;
     258                        paramPrefix += "p";
     259                        std::list< Declaration * > oldDecls;
     260                        oldDecls.splice( oldDecls.end(), declsToAddBefore );
     261
     262                        appExpr->acceptMutator( *visitor );
     263                        // Write recursive specializations into the thunk body.
     264                        for ( Declaration * decl : declsToAddBefore ) {
     265                                thunkFunc->statements->kids.push_back( new DeclStmt( decl ) );
     266                        }
     267
     268                        declsToAddBefore = std::move( oldDecls );
     269                        paramPrefix = oldParamPrefix;
     270                }
    262271
    263272                // add return (or valueless expression) to the thunk
     
    270279                thunkFunc->statements->kids.push_back( appStmt );
    271280
    272                 // add thunk definition to queue of statements to add
    273                 stmtsToAddBefore.push_back( new DeclStmt( thunkFunc ) );
     281                // Add the thunk definition (converted to DeclStmt if appproprate).
     282                declsToAddBefore.push_back( thunkFunc );
    274283                // return address of thunk function as replacement expression
    275284                return new AddressExpr( new VariableExpr( thunkFunc ) );
  • src/GenPoly/module.mk

    r3c64c668 r58fe85a  
    1616
    1717SRC += GenPoly/Box.cc \
     18       GenPoly/Box.h \
     19       GenPoly/ErasableScopedMap.h \
     20       GenPoly/FindFunction.cc \
     21       GenPoly/FindFunction.h \
    1822       GenPoly/GenPoly.cc \
     23       GenPoly/GenPoly.h \
     24       GenPoly/InstantiateGeneric.cc \
     25       GenPoly/InstantiateGeneric.h \
     26       GenPoly/Lvalue.cc \
     27       GenPoly/Lvalue.h \
     28       GenPoly/ScopedSet.h \
    1929       GenPoly/ScrubTyVars.cc \
    20        GenPoly/Lvalue.cc \
     30       GenPoly/ScrubTyVars.h \
    2131       GenPoly/Specialize.cc \
    22        GenPoly/FindFunction.cc \
    23        GenPoly/InstantiateGeneric.cc
     32       GenPoly/Specialize.h
    2433
    25 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/Lvalue.cc
     34SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/GenPoly.h GenPoly/Lvalue.cc GenPoly/Lvalue.h
    2635
  • src/InitTweak/FixGlobalInit.cc

    r3c64c668 r58fe85a  
    3434#include "SynTree/Visitor.h"       // for acceptAll, Visitor
    3535
     36#include "AST/Expr.hpp"
     37#include "AST/Node.hpp"
     38#include "AST/Pass.hpp"
     39
    3640namespace InitTweak {
    3741        class GlobalFixer : public WithShortCircuiting {
     
    5054                FunctionDecl * initFunction;
    5155                FunctionDecl * destroyFunction;
     56        };
     57
     58        class GlobalFixer_new : public ast::WithShortCircuiting {
     59        public:
     60                void previsit (const ast::ObjectDecl *);
     61                void previsit (const ast::FunctionDecl *) { visit_children = false; }
     62                void previsit (const ast::StructDecl *) { visit_children = false; }
     63                void previsit (const ast::UnionDecl *) { visit_children = false; }
     64                void previsit (const ast::EnumDecl *) { visit_children = false; }
     65                void previsit (const ast::TraitDecl *) { visit_children = false; }
     66                void previsit (const ast::TypeDecl *) { visit_children = false; }
     67
     68                std::list< ast::ptr<ast::Stmt> > initStmts;
     69                std::list< ast::ptr<ast::Stmt> > destroyStmts;
    5270        };
    5371
     
    91109        }
    92110
     111        void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
     112                ast::Pass<GlobalFixer_new> fixer;
     113                accept_all(translationUnit, fixer);
     114
     115                if ( !fixer.core.initStmts.empty() ) {
     116                        std::vector<ast::ptr<ast::Expr>> ctorParams;
     117                        if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int({}, 200));
     118                        auto initFunction = new ast::FunctionDecl({}, "__global_init__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.initStmts)),
     119                                ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("constructor", std::move(ctorParams))});
     120
     121                        translationUnit.decls.emplace_back( initFunction );
     122                } // if
     123
     124                if ( !fixer.core.destroyStmts.empty() ) {
     125                        std::vector<ast::ptr<ast::Expr>> dtorParams;
     126                        if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int({}, 200));
     127                        auto destroyFunction = new ast::FunctionDecl({}, "__global_destroy__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.destroyStmts)),
     128                                ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("destructor", std::move(dtorParams))});
     129
     130                        translationUnit.decls.emplace_back(destroyFunction);
     131                } // if
     132        }
     133
    93134        void GlobalFixer::previsit( ObjectDecl *objDecl ) {
    94135                std::list< Statement * > & initStatements = initFunction->get_statements()->get_kids();
     
    112153                        } // if
    113154                        if ( Statement * ctor = ctorInit->ctor ) {
     155                                addDataSectonAttribute( objDecl );
    114156                                initStatements.push_back( ctor );
    115157                                objDecl->init = nullptr;
     
    126168        }
    127169
     170        void GlobalFixer_new::previsit(const ast::ObjectDecl * objDecl) {
     171                auto mutDecl = mutate(objDecl);
     172                assertf(mutDecl == objDecl, "Global object decl must be unique");
     173                if ( auto ctorInit = objDecl->init.as<ast::ConstructorInit>() ) {
     174                        // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     175                        assert( ! ctorInit->ctor || ! ctorInit->init );
     176
     177                        const ast::Stmt * dtor = ctorInit->dtor;
     178                        if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
     179                                // don't need to call intrinsic dtor, because it does nothing, but
     180                                // non-intrinsic dtors must be called
     181                                destroyStmts.push_front( dtor );
     182                                // ctorInit->dtor = nullptr;
     183                        } // if
     184                        if ( const ast::Stmt * ctor = ctorInit->ctor ) {
     185                                addDataSectionAttribute(mutDecl);
     186                                initStmts.push_back( ctor );
     187                                mutDecl->init = nullptr;
     188                                // ctorInit->ctor = nullptr;
     189                        } else if ( const ast::Init * init = ctorInit->init ) {
     190                                mutDecl->init = init;
     191                                // ctorInit->init = nullptr;
     192                        } else {
     193                                // no constructor and no initializer, which is okay
     194                                mutDecl->init = nullptr;
     195                        } // if
     196                        // delete ctorInit;
     197                } // if
     198        }
     199
    128200        // only modify global variables
    129201        void GlobalFixer::previsit( FunctionDecl * ) { visit_children = false; }
  • src/InitTweak/FixGlobalInit.h

    r3c64c668 r58fe85a  
    1919#include <string>  // for string
    2020
     21#include <AST/Fwd.hpp>
     22
     23
    2124class Declaration;
    2225
     
    2629        /// function is for library code.
    2730        void fixGlobalInit( std::list< Declaration * > & translationUnit, bool inLibrary );
     31        void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary );
    2832} // namespace
    2933
  • src/InitTweak/FixInit.cc

    r3c64c668 r58fe85a  
    219219                };
    220220
    221                 struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
     221                struct SplitExpressions : public WithShortCircuiting, /*public WithTypeSubstitution, */public WithStmtsToAdd {
    222222                        /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
    223223                        static void split( std::list< Declaration * > &translationUnit );
     
    802802                                if ( Statement * ctor = ctorInit->get_ctor() ) {
    803803                                        if ( objDecl->get_storageClasses().is_static ) {
     804
     805                                                // The ojbect needs to go in the data section, regardless of dtor complexity below.
     806                                                // The attribute works, and is meant to apply, both for leaving the static local alone,
     807                                                // and for hoisting it out as a static global.
     808                                                addDataSectonAttribute( objDecl );
     809
    804810                                                // originally wanted to take advantage of gcc nested functions, but
    805811                                                // we get memory errors with this approach. To remedy this, the static
  • src/InitTweak/FixInit.h

    r3c64c668 r58fe85a  
    2020
    2121class Declaration;
     22namespace ast {
     23        struct TranslationUnit;
     24}
    2225
    2326namespace InitTweak {
    2427        /// replace constructor initializers with expression statements and unwrap basic C-style initializers
    2528        void fix( std::list< Declaration * > & translationUnit, bool inLibrary );
     29
     30        void fix( ast::TranslationUnit & translationUnit, bool inLibrary);
    2631} // namespace
    2732
  • src/InitTweak/GenInit.cc

    r3c64c668 r58fe85a  
    2626#include "AST/Node.hpp"
    2727#include "AST/Stmt.hpp"
     28#include "CompilationState.h"
    2829#include "CodeGen/OperatorTable.h"
    2930#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
     
    121122        };
    122123
     124        struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
     125                /// hoist dimension from array types in object declaration so that it uses a single
     126                /// const variable of type size_t, so that side effecting array dimensions are only
     127                /// computed once.
     128                static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
     129
     130                void premutate( ObjectDecl * objectDecl );
     131                DeclarationWithType * postmutate( ObjectDecl * objectDecl );
     132                void premutate( FunctionDecl *functionDecl );
     133                // should not traverse into any of these declarations to find objects
     134                // that need to be constructed or destructed
     135                void premutate( AggregateDecl * ) { visit_children = false; }
     136                void premutate( NamedTypeDecl * ) { visit_children = false; }
     137                void premutate( FunctionType * ) { visit_children = false; }
     138
     139                void hoist( Type * type );
     140
     141                Type::StorageClasses storageClasses;
     142                bool inFunction = false;
     143        };
     144
    123145        void genInit( std::list< Declaration * > & translationUnit ) {
     146                if (!useNewAST) {
     147                        HoistArrayDimension::hoistArrayDimension( translationUnit );
     148                }
     149                else {
     150                        HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
     151                }
    124152                fixReturnStatements( translationUnit );
    125                 HoistArrayDimension::hoistArrayDimension( translationUnit );
    126                 CtorDtor::generateCtorDtor( translationUnit );
     153
     154                if (!useNewAST) {
     155                        CtorDtor::generateCtorDtor( translationUnit );
     156                }
    127157        }
    128158
     
    196226                        arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
    197227                        // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
     228                        // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
     229                        // still try to detect constant expressions
    198230                        if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    199231
     
    210242
    211243        void HoistArrayDimension::premutate( FunctionDecl * ) {
     244                GuardValue( inFunction );
     245                inFunction = true;
     246        }
     247
     248        // precompute array dimension expression, because constructor generation may duplicate it,
     249        // which would be incorrect if it is a side-effecting computation.
     250        void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
     251                PassVisitor<HoistArrayDimension_NoResolve> hoister;
     252                mutateAll( translationUnit, hoister );
     253        }
     254
     255        void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
     256                GuardValue( storageClasses );
     257                storageClasses = objectDecl->get_storageClasses();
     258        }
     259
     260        DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
     261                hoist( objectDecl->get_type() );
     262                return objectDecl;
     263        }
     264
     265        void HoistArrayDimension_NoResolve::hoist( Type * type ) {
     266                // if in function, generate const size_t var
     267                static UniqueName dimensionName( "_array_dim" );
     268
     269                // C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
     270                if ( ! inFunction ) return;
     271                if ( storageClasses.is_static ) return;
     272
     273                if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
     274                        if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
     275                        // don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
     276                        // xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
     277                        // still try to detect constant expressions
     278                        if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
     279
     280                        ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
     281                        arrayDimension->get_type()->set_const( true );
     282
     283                        arrayType->set_dimension( new VariableExpr( arrayDimension ) );
     284                        declsToAddBefore.push_back( arrayDimension );
     285
     286                        hoist( arrayType->get_base() );
     287                        return;
     288                }
     289        }
     290
     291        void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
    212292                GuardValue( inFunction );
    213293                inFunction = true;
     
    245325        }
    246326
     327        // why is this not just on FunctionDecl?
    247328        void ManagedTypes::handleDWT( DeclarationWithType * dwt ) {
    248329                // if this function is a user-defined constructor or destructor, mark down the type as "managed"
     
    275356        void ManagedTypes::endScope() { managedTypes.endScope(); }
    276357
     358        bool ManagedTypes_new::isManaged( const ast::Type * type ) const {
     359                // references are never constructed
     360                if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
     361                if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
     362                        // tuple is also managed if any of its components are managed
     363                        for (auto & component : tupleType->types) {
     364                                if (isManaged(component)) return true;
     365                        }
     366                }
     367                // need to clear and reset qualifiers when determining if a type is managed
     368                // ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
     369                auto tmp = shallowCopy(type);
     370                tmp->qualifiers = {};
     371                // delete tmp at return
     372                ast::ptr<ast::Type> guard = tmp;
     373                // 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)
     374                return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
     375        }
     376
     377        bool ManagedTypes_new::isManaged( const ast::ObjectDecl * objDecl ) const {
     378                const ast::Type * type = objDecl->type;
     379                while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
     380                        // must always construct VLAs with an initializer, since this is an error in C
     381                        if ( at->isVarLen && objDecl->init ) return true;
     382                        type = at->base;
     383                }
     384                return isManaged( type );
     385        }
     386
     387        void ManagedTypes_new::handleDWT( const ast::DeclWithType * dwt ) {
     388                // if this function is a user-defined constructor or destructor, mark down the type as "managed"
     389                if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
     390                        auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
     391                        assert( ! params.empty() );
     392                        // Type * type = InitTweak::getPointerBase( params.front() );
     393                        // assert( type );
     394                        managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
     395                }
     396        }
     397
     398        void ManagedTypes_new::handleStruct( const ast::StructDecl * aggregateDecl ) {
     399                // don't construct members, but need to take note if there is a managed member,
     400                // because that means that this type is also managed
     401                for ( auto & member : aggregateDecl->members ) {
     402                        if ( auto field = member.as<ast::ObjectDecl>() ) {
     403                                if ( isManaged( field ) ) {
     404                                        // generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
     405                                        // polymorphic constructors make generic types managed types
     406                                        ast::StructInstType inst( aggregateDecl );
     407                                        managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
     408                                        break;
     409                                }
     410                        }
     411                }
     412        }
     413
     414        void ManagedTypes_new::beginScope() { managedTypes.beginScope(); }
     415        void ManagedTypes_new::endScope() { managedTypes.endScope(); }
     416
    277417        ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg ) {
    278418                // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
     
    283423                assert( stmts.size() <= 1 );
    284424                return stmts.size() == 1 ? strict_dynamic_cast< ImplicitCtorDtorStmt * >( stmts.front() ) : nullptr;
     425
     426        }
     427
     428        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
     429                assertf(objDecl, "genCtorDtor passed null objDecl");
     430                InitExpander_new srcParam(arg);
     431                return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
    285432        }
    286433
     
    363510        // constructable object
    364511        InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
     512        ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
    365513       
    366514        ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
    367                 srcParam, new ast::VariableExpr{ loc, objDecl }, loc, "?{}", objDecl );
     515                srcParam, dstParam, loc, "?{}", objDecl );
    368516        ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
    369                 nullParam, new ast::VariableExpr{ loc, objDecl }, loc, "^?{}", objDecl,
     517                nullParam, dstParam, loc, "^?{}", objDecl,
    370518                SymTab::LoopBackward );
    371519       
  • src/InitTweak/GenInit.h

    r3c64c668 r58fe85a  
    3333        /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
    3434        ImplicitCtorDtorStmt * genCtorDtor( const std::string & fname, ObjectDecl * objDecl, Expression * arg = nullptr );
     35        ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
    3536
    3637        /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
     
    5152                GenPoly::ScopedSet< std::string > managedTypes;
    5253        };
     54
     55        class ManagedTypes_new {
     56        public:
     57                bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed
     58                bool isManaged( const ast::Type * type ) const; // determine if type is managed
     59
     60                void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor
     61                void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed
     62
     63                void beginScope();
     64                void endScope();
     65        private:
     66                GenPoly::ScopedSet< std::string > managedTypes;
     67        };
    5368} // namespace
    5469
  • src/InitTweak/InitTweak.cc

    r3c64c668 r58fe85a  
    8787                };
    8888
     89                struct HasDesignations_new : public ast::WithShortCircuiting {
     90                        bool result = false;
     91
     92                        void previsit( const ast::Node * ) {
     93                                // short circuit if we already know there are designations
     94                                if ( result ) visit_children = false;
     95                        }
     96
     97                        void previsit( const ast::Designation * des ) {
     98                                // short circuit if we already know there are designations
     99                                if ( result ) visit_children = false;
     100                                else if ( ! des->designators.empty() ) {
     101                                        result = true;
     102                                        visit_children = false;
     103                                }
     104                        }
     105                };
     106
     107                struct InitDepthChecker_new : public ast::WithGuards {
     108                        bool result = true;
     109                        const ast::Type * type;
     110                        int curDepth = 0, maxDepth = 0;
     111                        InitDepthChecker_new( const ast::Type * type ) : type( type ) {
     112                                const ast::Type * t = type;
     113                                while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
     114                                        maxDepth++;
     115                                        t = at->base;
     116                                }
     117                                maxDepth++;
     118                        }
     119                        void previsit( ListInit * ) {
     120                                curDepth++;
     121                                GuardAction( [this]() { curDepth--; } );
     122                                if ( curDepth > maxDepth ) result = false;
     123                        }
     124                };
     125
    89126                struct InitFlattener_old : public WithShortCircuiting {
    90127                        void previsit( SingleInit * singleInit ) {
     
    124161        }
    125162
     163        bool isDesignated( const ast::Init * init ) {
     164                ast::Pass<HasDesignations_new> finder;
     165                maybe_accept( init, finder );
     166                return finder.core.result;
     167        }
     168
     169        bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
     170                ast::Pass<InitDepthChecker_new> checker( objDecl->type );
     171                maybe_accept( objDecl->init.get(), checker );
     172                return checker.core.result;
     173        }
     174
    126175std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
    127176        ast::Pass< InitFlattener_new > flattener;
    128177        maybe_accept( init, flattener );
    129         return std::move( flattener.pass.argList );
     178        return std::move( flattener.core.argList );
    130179}
    131180
     
    358407                        if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) {
    359408                                for ( const ast::Init * init : *listInit ) {
    360                                         buildCallExpr( callExpr, index, dimension, init, out );
     409                                        buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
    361410                                }
    362411                        } else {
    363                                 buildCallExpr( callExpr, index, dimension, init, out );
     412                                buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
    364413                        }
    365414                } else {
     
    498547        }
    499548
     549        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
     550                assertf( func, "getParamThis: nullptr ftype" );
     551                auto & params = func->params;
     552                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( func ).c_str());
     553                return params.front().strict_as<ast::ObjectDecl>();
     554        }
     555
    500556        bool tryConstruct( DeclarationWithType * dwt ) {
    501557                ObjectDecl * objDecl = dynamic_cast< ObjectDecl * >( dwt );
     
    511567        }
    512568
     569        bool tryConstruct( const ast::DeclWithType * dwt ) {
     570                auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );
     571                if ( ! objDecl ) return false;
     572                return (objDecl->init == nullptr ||
     573                                ( objDecl->init != nullptr && objDecl->init->maybeConstructed ))
     574                        && ! objDecl->storage.is_extern
     575                        && isConstructable( objDecl->type );
     576        }
     577
     578        bool isConstructable( const ast::Type * type ) {
     579                return ! dynamic_cast< const ast::VarArgsType * >( type ) && ! dynamic_cast< const ast::ReferenceType * >( type )
     580                && ! dynamic_cast< const ast::FunctionType * >( type ) && ! Tuples::isTtype( type );
     581        }
     582
    513583        struct CallFinder_old {
    514584                CallFinder_old( const std::list< std::string > & names ) : names( names ) {}
     
    536606
    537607        struct CallFinder_new final {
    538                 std::vector< ast::ptr< ast::Expr > > matches;
     608                std::vector< const ast::Expr * > matches;
    539609                const std::vector< std::string > names;
    540610
     
    558628        }
    559629
    560         std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt ) {
     630        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
    561631                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    562632                maybe_accept( stmt, finder );
    563                 return std::move( finder.pass.matches );
     633                return std::move( finder.core.matches );
    564634        }
    565635
     
    696766                template <typename Predicate>
    697767                bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
    698                         std::vector< ast::ptr< ast::Expr > > callExprs = collectCtorDtorCalls( stmt );
     768                        std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
    699769                        return std::all_of( callExprs.begin(), callExprs.end(), pred );
    700770                }
     
    9391009        }
    9401010
     1011        // looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards
     1012        // following passes may accidentally resolve this expression if returned as untyped...
     1013        ast::Expr * createBitwiseAssignment (const ast::Expr * dst, const ast::Expr * src) {
     1014                static ast::ptr<ast::FunctionDecl> assign = nullptr;
     1015                if (!assign) {
     1016                        auto td = new ast::TypeDecl({}, "T", {}, nullptr, ast::TypeDecl::Dtype, true);
     1017                        assign = new ast::FunctionDecl({}, "?=?", {},
     1018                        { new ast::ObjectDecl({}, "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
     1019                          new ast::ObjectDecl({}, "_src", new ast::TypeInstType("T", td))},
     1020                        { new ast::ObjectDecl({}, "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic);
     1021                }
     1022                if (dst->result.as<ast::ReferenceType>()) {
     1023                        for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
     1024                                dst = new ast::AddressExpr(dst);
     1025                        }
     1026                }
     1027                else {
     1028                        dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
     1029                }
     1030                if (src->result.as<ast::ReferenceType>()) {
     1031                        for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
     1032                                src = new ast::AddressExpr(src);
     1033                        }
     1034                }
     1035                return new ast::ApplicationExpr(dst->location, ast::VariableExpr::functionPointer(dst->location, assign), {dst, src});
     1036        }
     1037
    9411038        struct ConstExprChecker : public WithShortCircuiting {
    9421039                // most expressions are not const expr
     
    9791076        };
    9801077
     1078        struct ConstExprChecker_new : public ast::WithShortCircuiting {
     1079                // most expressions are not const expr
     1080                void previsit( const ast::Expr * ) { result = false; visit_children = false; }
     1081
     1082                void previsit( const ast::AddressExpr *addressExpr ) {
     1083                        visit_children = false;
     1084                        const ast::Expr * arg = addressExpr->arg;
     1085
     1086                        // address of a variable or member expression is constexpr
     1087                        if ( ! dynamic_cast< const ast::NameExpr * >( arg )
     1088                        && ! dynamic_cast< const ast::VariableExpr * >( arg )
     1089                        && ! dynamic_cast< const ast::MemberExpr * >( arg )
     1090                        && ! dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;
     1091                }
     1092
     1093                // these expressions may be const expr, depending on their children
     1094                void previsit( const ast::SizeofExpr * ) {}
     1095                void previsit( const ast::AlignofExpr * ) {}
     1096                void previsit( const ast::UntypedOffsetofExpr * ) {}
     1097                void previsit( const ast::OffsetofExpr * ) {}
     1098                void previsit( const ast::OffsetPackExpr * ) {}
     1099                void previsit( const ast::CommaExpr * ) {}
     1100                void previsit( const ast::LogicalExpr * ) {}
     1101                void previsit( const ast::ConditionalExpr * ) {}
     1102                void previsit( const ast::CastExpr * ) {}
     1103                void previsit( const ast::ConstantExpr * ) {}
     1104
     1105                void previsit( const ast::VariableExpr * varExpr ) {
     1106                        visit_children = false;
     1107
     1108                        if ( auto inst = varExpr->result.as<ast::EnumInstType>() ) {
     1109                                long long int value;
     1110                                if ( inst->base->valueOf( varExpr->var, value ) ) {
     1111                                        // enumerators are const expr
     1112                                        return;
     1113                                }
     1114                        }
     1115                        result = false;
     1116                }
     1117
     1118                bool result = true;
     1119        };
     1120
    9811121        bool isConstExpr( Expression * expr ) {
    9821122                if ( expr ) {
     
    9981138        }
    9991139
     1140        bool isConstExpr( const ast::Expr * expr ) {
     1141                if ( expr ) {
     1142                        ast::Pass<ConstExprChecker_new> checker;
     1143                        expr->accept( checker );
     1144                        return checker.core.result;
     1145                }
     1146                return true;
     1147        }
     1148
     1149        bool isConstExpr( const ast::Init * init ) {
     1150                if ( init ) {
     1151                        ast::Pass<ConstExprChecker_new> checker;
     1152                        init->accept( checker );
     1153                        return checker.core.result;
     1154                } // if
     1155                // for all intents and purposes, no initializer means const expr
     1156                return true;
     1157        }
     1158
    10001159        bool isConstructor( const std::string & str ) { return str == "?{}"; }
    10011160        bool isDestructor( const std::string & str ) { return str == "^?{}"; }
     
    10261185                if ( ftype->params.size() != 2 ) return false;
    10271186
    1028                 const ast::Type * t1 = getPointerBase( ftype->params.front()->get_type() );
     1187                const ast::Type * t1 = getPointerBase( ftype->params.front() );
    10291188                if ( ! t1 ) return false;
    1030                 const ast::Type * t2 = ftype->params.back()->get_type();
     1189                const ast::Type * t2 = ftype->params.back();
    10311190
    10321191                return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2, ast::SymbolTable{} );
     
    10551214                return isCopyFunction( decl, "?{}" );
    10561215        }
     1216
     1217        void addDataSectonAttribute( ObjectDecl * objDecl ) {
     1218                Type *strLitT = new PointerType( Type::Qualifiers( ),
     1219                        new BasicType( Type::Qualifiers( ), BasicType::Char ) );
     1220                std::list< Expression * > attr_params;
     1221                attr_params.push_back(
     1222                        new ConstantExpr( Constant( strLitT, "\".data#\"", std::nullopt ) ) );
     1223                objDecl->attributes.push_back(new Attribute("section", attr_params));
     1224        }
     1225
     1226        void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
     1227                auto strLitT = new ast::PointerType(new ast::BasicType(ast::BasicType::Char));
     1228                objDecl->attributes.push_back(new ast::Attribute("section", {new ast::ConstantExpr(objDecl->location, strLitT, "\".data#\"", std::nullopt)}));
     1229        }
     1230
    10571231}
  • src/InitTweak/InitTweak.h

    r3c64c668 r58fe85a  
    3838        /// returns the first parameter of a constructor/destructor/assignment function
    3939        ObjectDecl * getParamThis( FunctionType * ftype );
     40        const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
    4041
    4142        /// generate a bitwise assignment operation.
    4243        ApplicationExpr * createBitwiseAssignment( Expression * dst, Expression * src );
     44
     45        ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
    4346
    4447        /// transform Initializer into an argument list that can be passed to a call expression
     
    4851        /// True if the resolver should try to construct dwt
    4952        bool tryConstruct( DeclarationWithType * dwt );
     53        bool tryConstruct( const ast::DeclWithType * dwt );
    5054
    5155        /// True if the type can have a user-defined constructor
    5256        bool isConstructable( Type * t );
     57        bool isConstructable( const ast::Type * t );
    5358
    5459        /// True if the Initializer contains designations
    5560        bool isDesignated( Initializer * init );
     61        bool isDesignated( const ast::Init * init );
    5662
    5763        /// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
    5864        /// type, where the depth of its type is the number of nested ArrayTypes + 1
    5965        bool checkInitDepth( ObjectDecl * objDecl );
     66        bool checkInitDepth( const ast::ObjectDecl * objDecl );
    6067
    6168        /// returns the declaration of the function called by the expr (must be ApplicationExpr or UntypedExpr)
     
    7986        /// get all Ctor/Dtor call expressions from a Statement
    8087        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    81         std::vector< ast::ptr< ast::Expr > > collectCtorDtorCalls( const ast::Stmt * stmt );
     88        std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
    8289
    8390        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
     
    102109        bool isConstExpr( Expression * expr );
    103110        bool isConstExpr( Initializer * init );
     111
     112        bool isConstExpr( const ast::Expr * expr );
     113        bool isConstExpr( const ast::Init * init );
     114
     115        /// Modifies objDecl to have:
     116        ///    __attribute__((section (".data#")))
     117        /// which makes gcc put the declared variable in the data section,
     118        /// which is helpful for global constants on newer gcc versions,
     119        /// so that CFA's generated initialization won't segfault when writing it via a const cast.
     120        /// The trailing # is an injected assembly comment, to suppress the "a" in
     121        ///    .section .data,"a"
     122        ///    .section .data#,"a"
     123        /// to avoid assembler warning "ignoring changed section attributes for .data"
     124        void addDataSectonAttribute( ObjectDecl * objDecl );
     125
     126        void addDataSectionAttribute( ast::ObjectDecl * objDecl );
    104127
    105128        class InitExpander_old {
  • src/InitTweak/module.mk

    r3c64c668 r58fe85a  
    1515###############################################################################
    1616
    17 SRC += InitTweak/GenInit.cc \
     17SRC += \
     18        InitTweak/FixGlobalInit.cc \
     19        InitTweak/FixGlobalInit.h \
    1820        InitTweak/FixInit.cc \
    19         InitTweak/FixGlobalInit.cc \
    20         InitTweak/InitTweak.cc
     21        InitTweak/FixInit.h \
     22        InitTweak/GenInit.cc \
     23        InitTweak/GenInit.h \
     24        InitTweak/InitTweak.cc \
     25        InitTweak/InitTweak.h \
     26        InitTweak/FixInitNew.cpp
    2127
    22 SRCDEMANGLE += InitTweak/GenInit.cc \
    23         InitTweak/InitTweak.cc
     28SRCDEMANGLE += \
     29        InitTweak/GenInit.cc \
     30        InitTweak/GenInit.h \
     31        InitTweak/InitTweak.cc \
     32        InitTweak/InitTweak.h
    2433
  • src/Makefile.am

    r3c64c668 r58fe85a  
    2020
    2121SRC = main.cc \
     22      CompilationState.cc \
     23      CompilationState.h \
    2224      MakeLibCfa.cc \
    23       CompilationState.cc
     25        MakeLibCfa.h
    2426
    2527SRCDEMANGLE = CompilationState.cc
     
    6668___driver_cfa_cpp_SOURCES = $(SRC)
    6769___driver_cfa_cpp_LDADD = -ldl $(LIBPROFILER) $(LIBTCMALLOC)
     70EXTRA_DIST = include/cassert include/optional BasicTypes-gen.cc
    6871
    6972AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++14 $(TCMALLOCFLAG)
  • src/Parser/DeclarationNode.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 15:32:22 2019
    13 // Update Count     : 1133
     12// Last Modified On : Thu Oct  8 08:03:38 2020
     13// Update Count     : 1135
    1414//
    1515
     
    10161016                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
    10171017                                dwt->location = cur->location;
    1018                                 * out++ = dwt;
     1018                                *out++ = dwt;
    10191019                        } else if ( StructDecl * agg = dynamic_cast< StructDecl * >( decl ) ) {
    10201020                                // e.g., int foo(struct S) {}
     
    10221022                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    10231023                                obj->location = cur->location;
    1024                                 * out++ = obj;
     1024                                *out++ = obj;
    10251025                                delete agg;
    10261026                        } else if ( UnionDecl * agg = dynamic_cast< UnionDecl * >( decl ) ) {
     
    10291029                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    10301030                                obj->location = cur->location;
    1031                                 * out++ = obj;
     1031                                *out++ = obj;
    10321032                        } else if ( EnumDecl * agg = dynamic_cast< EnumDecl * >( decl ) ) {
    10331033                                // e.g., int foo(enum E) {}
     
    10351035                                auto obj = new ObjectDecl( "", Type::StorageClasses(), linkage, nullptr, inst, nullptr );
    10361036                                obj->location = cur->location;
    1037                                 * out++ = obj;
     1037                                *out++ = obj;
    10381038                        } // if
    10391039                } catch( SemanticErrorException & e ) {
     
    11151115        // SUE's cannot have function specifiers, either
    11161116        //
    1117         //    inlne _Noreturn struct S { ... };         // disallowed
    1118         //    inlne _Noreturn enum   E { ... };         // disallowed
     1117        //    inline _Noreturn struct S { ... };                // disallowed
     1118        //    inline _Noreturn enum   E { ... };                // disallowed
    11191119        if ( funcSpecs.any() ) {
    11201120                SemanticError( this, "invalid function specifier for " );
  • src/Parser/ExpressionNode.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 18 21:14:58 2019
    13 // Update Count     : 981
     12// Last Modified On : Thu Aug 20 14:01:46 2020
     13// Update Count     : 1076
    1414//
    1515
     
    6565
    6666void lnthSuffix( string & str, int & type, int & ltype ) {
     67        // 'u' can appear before or after length suffix
    6768        string::size_type posn = str.find_last_of( "lL" );
    6869
    6970        if ( posn == string::npos ) return;                                     // no suffix
    70         if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long
    71 
     71        size_t end = str.length() - 1;
     72        if ( posn == end ) { type = 3; return; }                        // no length after 'l' => long
     73       
    7274        string::size_type next = posn + 1;                                      // advance to length
    7375        if ( str[next] == '3' ) {                                                       // 32
     
    8486                } // if
    8587        } // if
    86         // remove "lL" for these cases because it may not imply long
    87         str.erase( posn );                                                                      // remove length
     88
     89        char fix = '\0';
     90        if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ?
     91        str.erase( posn );                                                                      // remove length suffix and possibly uU
     92        if ( type == 5 ) {                                                                      // L128 does not need uU
     93                end = str.length() - 1;
     94                if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove
     95        } else if ( fix != '\0' ) str += fix;                           // put 'uU' back if removed
    8896} // lnthSuffix
    8997
     
    108116} // valueToType
    109117
     118static void scanbin( string & str, unsigned long long int & v ) {
     119        v = 0;
     120        size_t last = str.length() - 1;                                         // last subscript of constant
     121        for ( unsigned int i = 2;; ) {                                          // ignore prefix
     122                if ( str[i] == '1' ) v |= 1;
     123                i += 1;
     124          if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
     125                v <<= 1;
     126        } // for
     127} // scanbin
     128
    110129Expression * build_constantInteger( string & str ) {
    111130        static const BasicType::Kind kind[2][6] = {
    112131                // short (h) must be before char (hh) because shorter type has the longer suffix
    113                 { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, BasicType::SignedInt128, },
    114                 { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::UnsignedInt128, },
     132                { BasicType::ShortSignedInt, BasicType::SignedChar, BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt, /* BasicType::SignedInt128 */ BasicType::LongLongSignedInt, },
     133                { BasicType::ShortUnsignedInt, BasicType::UnsignedChar, BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt, /* BasicType::UnsignedInt128 */ BasicType::LongLongUnsignedInt, },
    115134        };
    116135
     
    120139        }; // lnthsInt
    121140
    122         unsigned long long int v;                                                       // converted integral value
    123         size_t last = str.length() - 1;                                         // last subscript of constant
    124         Expression * ret;
    125         //string fred( str );
     141        string str2( "0x0" );
     142        unsigned long long int v, v2 = 0;                                       // converted integral value
     143        Expression * ret, * ret2;
    126144
    127145        int type = -1;                                                                          // 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
     
    139157        } // if
    140158
     159        string::size_type posn;
     160
     161        // 'u' can appear before or after length suffix
     162        if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true;
     163
     164        if ( isdigit( str[str.length() - 1] ) ) {                       // no suffix ?
     165                lnthSuffix( str, type, ltype );                                 // could have length suffix
     166        } else {
     167                // At least one digit in integer constant, so safe to backup while looking for suffix.
     168
     169                posn = str.find_last_of( "pP" );                                // pointer value
     170                if ( posn != string::npos ) { ltype = 5; str.erase( posn, 1 ); goto FINI; }
     171
     172                posn = str.find_last_of( "zZ" );                                // size_t
     173                if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; }
     174
     175                posn = str.rfind( "hh" );                                               // char
     176                if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
     177
     178                posn = str.rfind( "HH" );                                               // char
     179                if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
     180
     181                posn = str.find_last_of( "hH" );                                // short
     182                if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; }
     183
     184                posn = str.find_last_of( "nN" );                                // int (natural number)
     185                if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; }
     186
     187                if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; }
     188
     189                lnthSuffix( str, type, ltype );                                 // must be after check for "ll"
     190          FINI: ;
     191        } // if
     192
    141193        // Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate
    142194
     195#if ! defined(__SIZEOF_INT128__)
     196        if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target " + str );
     197#endif // ! __SIZEOF_INT128__
     198       
    143199        if ( str[0] == '0' ) {                                                          // radix character ?
    144200                dec = false;
    145201                if ( checkX( str[1] ) ) {                                               // hex constant ?
    146                         sscanf( (char *)str.c_str(), "%llx", &v );
     202                        if ( type < 5 ) {                                                       // not L128 ?
     203                                sscanf( (char *)str.c_str(), "%llx", &v );
     204#if defined(__SIZEOF_INT128__)
     205                        } else {                                                                        // hex int128 constant
     206                                unsigned int len = str.length();
     207                                if ( len > (2 + 16 + 16) ) SemanticError( yylloc, "128-bit hexadecimal constant to large " + str );
     208                          if ( len <= (2 + 16) ) goto FHEX1;            // hex digits < 2^64
     209                                str2 = "0x" + str.substr( len - 16 );
     210                                sscanf( (char *)str2.c_str(), "%llx", &v2 );
     211                                str = str.substr( 0, len - 16 );
     212                          FHEX1: ;
     213                                sscanf( (char *)str.c_str(), "%llx", &v );
     214#endif // __SIZEOF_INT128__
     215                        } // if
    147216                        //printf( "%llx %llu\n", v, v );
    148217                } else if ( checkB( str[1] ) ) {                                // binary constant ?
    149                         v = 0;                                                                          // compute value
    150                         for ( unsigned int i = 2;; ) {                          // ignore prefix
    151                                 if ( str[i] == '1' ) v |= 1;
    152                                 i += 1;
    153                           if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
    154                                 v <<= 1;
    155                         } // for
     218#if defined(__SIZEOF_INT128__)
     219                        unsigned int len = str.length();
     220                        if ( type == 5 && len > 2 + 64 ) {
     221                                if ( len > 2 + 64 + 64 ) SemanticError( yylloc, "128-bit binary constant to large " + str );
     222                                str2 = "0b" + str.substr( len - 64 );
     223                                str = str.substr( 0, len - 64 );
     224                                scanbin( str2, v2 );
     225                        } // if
     226#endif // __SIZEOF_INT128__
     227                        scanbin( str, v );
    156228                        //printf( "%#llx %llu\n", v, v );
    157229                } else {                                                                                // octal constant
    158                         sscanf( (char *)str.c_str(), "%llo", &v );
     230                        if ( type < 5 ) {                                                       // not L128 ?
     231                                sscanf( (char *)str.c_str(), "%llo", &v );
     232#if defined(__SIZEOF_INT128__)
     233                        } else {                                                                        // octal int128 constant
     234                                unsigned int len = str.length();
     235                                if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large " + str );
     236                                char buf[32];
     237                                if ( len <= 1 + 21 ) {                                  // value < 21 octal digitis
     238                                        sscanf( (char *)str.c_str(), "%llo", &v );
     239                                } else {
     240                                        sscanf( &str[len - 21], "%llo", &v );
     241                                        __int128 val = v;                                       // accumulate bits
     242                                        str[len - 21] ='\0';                            // shorten string
     243                                        sscanf( &str[len == 43 ? 1 : 0], "%llo", &v );
     244                                        val |= (__int128)v << 63;                       // store bits
     245                                        if ( len == 1 + 43 ) {                          // most significant 2 bits ?
     246                                                str[2] = '\0';                                  // shorten string
     247                                                sscanf( &str[1], "%llo", &v );  // process most significant 2 bits
     248                                                val |= (__int128)v << 126;              // store bits
     249                                        } // if
     250                                        v = val >> 64; v2 = (uint64_t)val;      // replace octal constant with 2 hex constants
     251                                        sprintf( buf, "%#llx", v2 );
     252                                        str2 = buf;
     253                                } // if
     254                                sprintf( buf, "%#llx", v );
     255                                str = buf;
     256#endif // __SIZEOF_INT128__
     257                        } // if
    159258                        //printf( "%#llo %llu\n", v, v );
    160259                } // if
    161260        } else {                                                                                        // decimal constant ?
    162                 sscanf( (char *)str.c_str(), "%llu", &v );
     261                if ( type < 5 ) {                                                               // not L128 ?
     262                        sscanf( (char *)str.c_str(), "%llu", &v );
     263#if defined(__SIZEOF_INT128__)
     264                } else {                                                                                // decimal int128 constant
     265                        #define P10_UINT64 10'000'000'000'000'000'000ULL // 19 zeroes
     266                        unsigned int len = str.length();
     267                        if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") )
     268                                SemanticError( yylloc, "128-bit decimal constant to large " + str );
     269                        char buf[32];
     270                        if ( len <= 19 ) {                                                      // value < 19 decimal digitis
     271                                sscanf( (char *)str.c_str(), "%llu", &v );
     272                        } else {
     273                                sscanf( &str[len - 19], "%llu", &v );
     274                                __int128 val = v;                                               // accumulate bits
     275                                str[len - 19] ='\0';                                    // shorten string
     276                                sscanf( &str[len == 39 ? 1 : 0], "%llu", &v );
     277                                val += (__int128)v * (__int128)P10_UINT64; // store bits
     278                                if ( len == 39 ) {                                              // most significant 2 bits ?
     279                                        str[1] = '\0';                                          // shorten string
     280                                        sscanf( &str[0], "%llu", &v );          // process most significant 2 bits
     281                                        val += (__int128)v * (__int128)P10_UINT64 * (__int128)P10_UINT64; // store bits
     282                                } // if
     283                                v = val >> 64; v2 = (uint64_t)val;              // replace decimal constant with 2 hex constants
     284                                sprintf( buf, "%#llx", v2 );
     285                                str2 = buf;
     286                        } // if
     287                        sprintf( buf, "%#llx", v );
     288                        str = buf;
     289#endif // __SIZEOF_INT128__
     290                } // if
    163291                //printf( "%llu\n", v );
    164292        } // if
    165293
    166         string::size_type posn;
    167 
    168         if ( isdigit( str[last] ) ) {                                           // no suffix ?
    169                 lnthSuffix( str, type, ltype );                                 // could have length suffix
    170                 if ( type == -1 ) {                                                             // no suffix
    171                         valueToType( v, dec, type, Unsigned );
    172                 } // if
    173         } else {
    174                 // At least one digit in integer constant, so safe to backup while looking for suffix.
    175 
    176                 posn = str.find_last_of( "pP" );
    177                 if ( posn != string::npos ) { valueToType( v, dec, type, Unsigned ); ltype = 5; str.erase( posn, 1 ); goto FINI; }
    178 
    179                 posn = str.find_last_of( "zZ" );
    180                 if ( posn != string::npos ) { Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 ); goto FINI; }
    181 
    182                 // 'u' can appear before or after length suffix
    183                 if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true;
    184 
    185                 posn = str.rfind( "hh" );
    186                 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
    187 
    188                 posn = str.rfind( "HH" );
    189                 if ( posn != string::npos ) { type = 1; str.erase( posn, 2 ); goto FINI; }
    190 
    191                 posn = str.find_last_of( "hH" );
    192                 if ( posn != string::npos ) { type = 0; str.erase( posn, 1 ); goto FINI; }
    193 
    194                 posn = str.find_last_of( "nN" );
    195                 if ( posn != string::npos ) { type = 2; str.erase( posn, 1 ); goto FINI; }
    196 
    197                 if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) { type = 4; goto FINI; }
    198 
    199                 lnthSuffix( str, type, ltype );                                 // must be after check for "ll"
    200                 if ( type == -1 ) {                                                             // only 'u' suffix ?
    201                         valueToType( v, dec, type, Unsigned );
    202                 } // if
    203           FINI: ;
    204         } // if
     294        if ( type == -1 ) {                                                                     // no suffix => determine type from value size
     295                valueToType( v, dec, type, Unsigned );
     296        } // if
     297        /* printf( "%s %llo %s %llo\n", str.c_str(), v, str2.c_str(), v2 ); */
    205298
    206299        //if ( !( 0 <= type && type <= 6 ) ) { printf( "%s %lu %d %s\n", fred.c_str(), fred.length(), type, str.c_str() ); }
     
    214307        } else if ( ltype != -1 ) {                                                     // explicit length ?
    215308                if ( ltype == 6 ) {                                                             // int128, (int128)constant
    216                         ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
     309//                      ret = new CastExpr( ret, new BasicType( Type::Qualifiers(), kind[Unsigned][type] ), false );
     310                        ret2 = new ConstantExpr( Constant( new BasicType( noQualifiers, BasicType::LongLongSignedInt ), str2, v2 ) );
     311                        ret = build_compoundLiteral( DeclarationNode::newBasicType( DeclarationNode::Int128 )->addType( DeclarationNode::newSignedNess( DeclarationNode::Unsigned ) ),
     312                                                                                 new InitializerNode( (InitializerNode *)(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true ) );
    217313                } else {                                                                                // explicit length, (length_type)constant
    218314                        ret = new CastExpr( ret, new TypeInstType( Type::Qualifiers(), lnthsInt[Unsigned][ltype], false ), false );
     
    342438                if ( str[1] == '8' ) goto Default;                              // utf-8 characters => array of char
    343439                // lookup type of associated typedef
    344                 strtype = new TypeInstType( Type::Qualifiers( Type::Const ), "char16_t", false );
     440                strtype = new TypeInstType( Type::Qualifiers( ), "char16_t", false );
    345441                break;
    346442          case 'U':
    347                 strtype = new TypeInstType( Type::Qualifiers( Type::Const ), "char32_t", false );
     443                strtype = new TypeInstType( Type::Qualifiers( ), "char32_t", false );
    348444                break;
    349445          case 'L':
    350                 strtype = new TypeInstType( Type::Qualifiers( Type::Const ), "wchar_t", false );
     446                strtype = new TypeInstType( Type::Qualifiers( ), "wchar_t", false );
    351447                break;
    352448          Default:                                                                                      // char default string type
    353449          default:
    354                 strtype = new BasicType( Type::Qualifiers( Type::Const ), BasicType::Char );
     450                strtype = new BasicType( Type::Qualifiers( ), BasicType::Char );
    355451        } // switch
    356452        ArrayType * at = new ArrayType( noQualifiers, strtype,
  • src/Parser/ParseNode.h

    r3c64c668 r58fe85a  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb  7 17:56:02 2020
    13 // Update Count     : 891
     12// Last Modified On : Sat Oct 24 03:53:54 2020
     13// Update Count     : 895
    1414//
    1515
     
    3737class Attribute;
    3838class Declaration;
    39 class DeclarationNode;
     39struct DeclarationNode;
    4040class DeclarationWithType;
    4141class ExpressionNode;
    4242class Initializer;
    43 class StatementNode;
     43struct StatementNode;
    4444
    4545//##############################################################################
     
    8686class InitializerNode : public ParseNode {
    8787  public:
    88         InitializerNode( ExpressionNode *, bool aggrp = false,  ExpressionNode * des = nullptr );
     88        InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
    8989        InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
    9090        InitializerNode( bool isDelete );
     
    205205struct TypeData;
    206206
    207 class DeclarationNode : public ParseNode {
    208   public:
     207struct DeclarationNode : public ParseNode {
    209208        // These enumerations must harmonize with their names in DeclarationNode.cc.
    210209        enum BasicType { Void, Bool, Char, Int, Int128,
     
    304303        bool get_inLine() const { return inLine; }
    305304        DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    306   public:
     305
    307306        DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
    308307
     
    360359//##############################################################################
    361360
    362 class StatementNode final : public ParseNode {
    363   public:
     361struct StatementNode final : public ParseNode {
    364362        StatementNode() { stmt = nullptr; }
    365363        StatementNode( Statement * stmt ) : stmt( stmt ) {}
     
    382380                os << stmt.get() << std::endl;
    383381        }
    384   private:
     382
    385383        std::unique_ptr<Statement> stmt;
    386384}; // StatementNode
     
    426424Statement * build_finally( StatementNode * stmt );
    427425Statement * build_compound( StatementNode * first );
     426StatementNode * maybe_build_compound( StatementNode * first );
    428427Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    429428Statement * build_directive( std::string * directive );
     429SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);
    430430WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when );
    431431WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing );
  • src/Parser/StatementNode.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Sat May 16 14:59:41 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug  4 09:39:25 2018
    13 // Update Count     : 363
     12// Last Modified On : Sat Oct 24 04:20:55 2020
     13// Update Count     : 383
    1414//
    1515
     
    249249} // build_finally
    250250
     251SuspendStmt * build_suspend( StatementNode * then, SuspendStmt::Type type ) {
     252        auto node = new SuspendStmt();
     253
     254        node->type = type;
     255
     256        std::list< Statement * > stmts;
     257        buildMoveList< Statement, StatementNode >( then, stmts );
     258        if(!stmts.empty()) {
     259                assert( stmts.size() == 1 );
     260                node->then = dynamic_cast< CompoundStmt * >( stmts.front() );
     261        }
     262
     263        return node;
     264}
     265
    251266WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
    252267        auto node = new WaitForStmt();
     
    330345} // build_compound
    331346
     347// A single statement in a control structure is always converted to a compound statement so subsequent generated code
     348// can be placed within this compound statement. Otherwise, code generation has to constantly check for a single
     349// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
     350// conical form for code generation.
     351StatementNode * maybe_build_compound( StatementNode * first ) {
     352        // Optimization: if the control-structure statement is a compound statement, do not wrap it.
     353        // e.g., if (...) {...} do not wrap the existing compound statement.
     354        if ( ! dynamic_cast<CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
     355                CompoundStmt * cs = new CompoundStmt();
     356                buildMoveList( first, cs->get_kids() );
     357                return new StatementNode( cs );
     358        } // if
     359        return first;
     360} // maybe_build_compound
     361
    332362Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    333363        std::list< Expression * > out, in;
  • src/Parser/TypeData.cc

    r3c64c668 r58fe85a  
    769769          case AggregateDecl::Struct:
    770770          case AggregateDecl::Coroutine:
     771          case AggregateDecl::Generator:
    771772          case AggregateDecl::Monitor:
    772773          case AggregateDecl::Thread:
     
    899900                ret = new TypeDecl( name, scs, typebuild( td->base ), TypeDecl::Dtype, true );
    900901        } // if
    901         buildList( td->symbolic.params, ret->get_parameters() );
    902902        buildList( td->symbolic.assertions, ret->get_assertions() );
    903903        ret->base->attributes.splice( ret->base->attributes.end(), attributes );
  • src/Parser/lex.ll

    r3c64c668 r58fe85a  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Sat Feb 15 11:05:50 2020
    13  * Update Count     : 737
     12 * Last Modified On : Tue Oct  6 18:15:41 2020
     13 * Update Count     : 743
    1414 */
    1515
     
    6262#define IDENTIFIER_RETURN()     RETURN_VAL( typedefTable.isKind( yytext ) )
    6363
    64 #ifdef HAVE_KEYWORDS_FLOATXX                                                            // GCC >= 7 => keyword, otherwise typedef
     64#ifdef HAVE_KEYWORDS_FLOATXX                                                    // GCC >= 7 => keyword, otherwise typedef
    6565#define FLOATXX(v) KEYWORD_RETURN(v);
    6666#else
    67 #define FLOATXX(v) IDENTIFIER_RETURN(); 
     67#define FLOATXX(v) IDENTIFIER_RETURN();
    6868#endif // HAVE_KEYWORDS_FLOATXX
    6969
     
    292292__restrict__    { KEYWORD_RETURN(RESTRICT); }                   // GCC
    293293return                  { KEYWORD_RETURN(RETURN); }
    294         /* resume                       { KEYWORD_RETURN(RESUME); }                             // CFA */
     294 /* resume                      { KEYWORD_RETURN(RESUME); }                             // CFA */
    295295short                   { KEYWORD_RETURN(SHORT); }
    296296signed                  { KEYWORD_RETURN(SIGNED); }
     
    301301_Static_assert  { KEYWORD_RETURN(STATICASSERT); }               // C11
    302302struct                  { KEYWORD_RETURN(STRUCT); }
    303         /* suspend                      { KEYWORD_RETURN(SUSPEND); }                    // CFA */
     303suspend                 { KEYWORD_RETURN(SUSPEND); }                    // CFA
    304304switch                  { KEYWORD_RETURN(SWITCH); }
    305305thread                  { KEYWORD_RETURN(THREAD); }                             // C11
  • src/Parser/module.mk

    r3c64c668 r58fe85a  
    1717BUILT_SOURCES = Parser/parser.hh
    1818
    19 AM_YFLAGS = -d -t -v
     19AM_YFLAGS = -d -t -v -Wno-yacc
    2020
    2121SRC += \
     
    2323       Parser/ExpressionNode.cc \
    2424       Parser/InitializerNode.cc \
     25       Parser/lex.ll \
    2526       Parser/ParseNode.cc \
     27       Parser/ParseNode.h \
     28       Parser/parser.yy \
     29       Parser/ParserTypes.h \
     30       Parser/parserutility.cc \
     31       Parser/parserutility.h \
    2632       Parser/StatementNode.cc \
    2733       Parser/TypeData.cc \
     34       Parser/TypeData.h \
    2835       Parser/TypedefTable.cc \
    29        Parser/lex.ll \
    30        Parser/parser.yy \
    31        Parser/parserutility.cc
     36       Parser/TypedefTable.h
    3237
    3338MOSTLYCLEANFILES += Parser/lex.cc Parser/parser.cc Parser/parser.hh Parser/parser.output
  • src/Parser/parser.yy

    r3c64c668 r58fe85a  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb 21 14:47:29 2020
    13 // Update Count     : 4468
     12// Last Modified On : Sat Oct 24 08:21:14 2020
     13// Update Count     : 4624
    1414//
    1515
     
    204204                        return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
    205205                } else {
    206                         SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr;
     206                        SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
    207207                } // if
    208208        } else {
    209                 SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed" ); return nullptr;
     209                SemanticError( yylloc, "Expression disallowed. Only loop-index name allowed." ); return nullptr;
    210210        } // if
    211211} // forCtrl
     
    278278%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
    279279%token SIZEOF OFFSETOF
    280 // %token SUSPEND RESUME                                                                        // CFA
     280// %token RESUME                                                                                        // CFA
     281%token SUSPEND                                                                                  // CFA
    281282%token ATTRIBUTE EXTENSION                                                              // GCC
    282283%token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
     
    328329%type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
    329330%type<en> comma_expression                              comma_expression_opt
    330 %type<en> argument_expression_list              argument_expression                     default_initialize_opt
     331%type<en> argument_expression_list_opt  argument_expression                     default_initialize_opt
    331332%type<ifctl> if_control_expression
    332333%type<fctl> for_control_expression              for_control_expression_list
     
    369370%type<decl> assertion assertion_list assertion_list_opt
    370371
    371 %type<en>   bit_subrange_size_opt bit_subrange_size
     372%type<en> bit_subrange_size_opt bit_subrange_size
    372373
    373374%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     
    623624                // equivalent to the old x[i,j].
    624625                { $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
    625         | postfix_expression '{' argument_expression_list '}' // CFA, constructor call
     626        | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
    626627                {
    627628                        Token fn;
     
    629630                        $$ = new ExpressionNode( new ConstructorExpr( build_func( new ExpressionNode( build_varref( fn ) ), (ExpressionNode *)( $1 )->set_last( $3 ) ) ) );
    630631                }
    631         | postfix_expression '(' argument_expression_list ')'
     632        | postfix_expression '(' argument_expression_list_opt ')'
    632633                { $$ = new ExpressionNode( build_func( $1, $3 ) ); }
    633634        | postfix_expression '`' identifier                                     // CFA, postfix call
     
    661662        | '(' type_no_function ')' '@' '{' initializer_list_opt comma_opt '}' // CFA, explicit C compound-literal
    662663                { $$ = new ExpressionNode( build_compoundLiteral( $2, (new InitializerNode( $6, true ))->set_maybeConstructed( false ) ) ); }
    663         | '^' primary_expression '{' argument_expression_list '}' // CFA, destructor call
     664        | '^' primary_expression '{' argument_expression_list_opt '}' // CFA, destructor call
    664665                {
    665666                        Token fn;
     
    669670        ;
    670671
    671 argument_expression_list:
     672argument_expression_list_opt:
    672673        // empty
    673674                { $$ = nullptr; }
    674675        | argument_expression
    675         | argument_expression_list ',' argument_expression
     676        | argument_expression_list_opt ',' argument_expression
    676677                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
    677678        ;
     
    792793        | '(' aggregate_control '&' ')' cast_expression         // CFA
    793794                { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
    794                 // VIRTUAL cannot be opt because of look ahead issues
    795795        | '(' VIRTUAL ')' cast_expression                                       // CFA
    796796                { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild< Expression >( $4 ), maybeMoveBuildType( nullptr ) ) ); }
     
    918918        conditional_expression
    919919        | unary_expression assignment_operator assignment_expression
    920                 { $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) ); }
     920                {
     921//                      if ( $2 == OperKinds::AtAssn ) {
     922//                              SemanticError( yylloc, "C @= assignment is currently unimplemented." ); $$ = nullptr;
     923//                      } else {
     924                                $$ = new ExpressionNode( build_binary_val( $2, $1, $3 ) );
     925//                      } // if
     926                }
    921927        | unary_expression '=' '{' initializer_list_opt comma_opt '}'
    922928                { SemanticError( yylloc, "Initializer assignment is currently unimplemented." ); $$ = nullptr; }
     
    959965
    960966tuple_expression_list:
    961         assignment_expression_opt
    962         | tuple_expression_list ',' assignment_expression_opt
     967        assignment_expression
     968        | '@'                                                                                           // CFA
     969                { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; }
     970        | tuple_expression_list ',' assignment_expression
    963971                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     972        | tuple_expression_list ',' '@'
     973                { SemanticError( yylloc, "Eliding tuple element with '@' is currently unimplemented." ); $$ = nullptr; }
    964974        ;
    965975
     
    10701080        IF '(' if_control_expression ')' statement                      %prec THEN
    10711081                // explicitly deal with the shift/reduce conflict on if/else
    1072                 { $$ = new StatementNode( build_if( $3, $5, nullptr ) ); }
     1082                { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), nullptr ) ); }
    10731083        | IF '(' if_control_expression ')' statement ELSE statement
    1074                 { $$ = new StatementNode( build_if( $3, $5, $7 ) ); }
     1084                { $$ = new StatementNode( build_if( $3, maybe_build_compound( $5 ), maybe_build_compound( $7 ) ) ); }
    10751085        ;
    10761086
     
    11201130
    11211131case_clause:                                                                                    // CFA
    1122         case_label_list statement                                       { $$ = $1->append_last_case( new StatementNode( build_compound( $2 ) ) ); }
     1132        case_label_list statement                                       { $$ = $1->append_last_case( maybe_build_compound( $2 ) ); }
    11231133        ;
    11241134
     
    11381148iteration_statement:
    11391149        WHILE '(' push if_control_expression ')' statement pop
    1140                 { $$ = new StatementNode( build_while( $4, $6 ) ); }
     1150                { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); }
    11411151        | WHILE '(' ')' statement                                                       // CFA => while ( 1 )
    1142                 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), $4 ) ); }
     1152                { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
    11431153        | DO statement WHILE '(' comma_expression ')' ';'
    1144                 { $$ = new StatementNode( build_do_while( $5, $2 ) ); }
     1154                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
    11451155        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    1146                 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), $2 ) ); }
     1156                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
    11471157        | FOR '(' push for_control_expression_list ')' statement pop
    1148                 { $$ = new StatementNode( build_for( $4, $6 ) ); }
     1158                { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); }
    11491159        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
    1150                 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), $4 ) ); }
     1160                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
    11511161        ;
    11521162
     
    11851195                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11861196                                                OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1187         | '=' comma_expression                                                                  // CFA
     1197        | '=' comma_expression                                                          // CFA
    11881198                { $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11891199                                                OperKinds::LEThan, $2->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
     
    11921202        | comma_expression inclexcl comma_expression '~' comma_expression // CFA
    11931203                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, $5 ); }
     1204        | comma_expression ';'                                                          // CFA
     1205                { $$ = forCtrl( new ExpressionNode( build_constantInteger( *new string( "0u" ) ) ), $1, nullptr, OperKinds::LThan, nullptr, nullptr ); }
    11941206        | comma_expression ';' comma_expression                         // CFA
    11951207                { $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11961208                                                OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    1197         | comma_expression ';' '=' comma_expression                             // CFA
     1209        | comma_expression ';' '=' comma_expression                     // CFA
    11981210                { $$ = forCtrl( $4, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
    11991211                                                OperKinds::LEThan, $4->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
     
    12591271        | RETURN '{' initializer_list_opt comma_opt '}' ';'
    12601272                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    1261         // | SUSPEND ';'
    1262         //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
    1263         // | SUSPEND compound_statement ';'
    1264         //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
     1273        | SUSPEND ';'
     1274                { $$ = new StatementNode( build_suspend( nullptr ) ); }
     1275        | SUSPEND compound_statement
     1276                { $$ = new StatementNode( build_suspend( $2 ) ); }
     1277        | SUSPEND COROUTINE ';'
     1278                { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); }
     1279        | SUSPEND COROUTINE compound_statement
     1280                { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); }
     1281        | SUSPEND GENERATOR ';'
     1282                { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); }
     1283        | SUSPEND GENERATOR compound_statement
     1284                { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); }
    12651285        | THROW assignment_expression_opt ';'                           // handles rethrow
    12661286                { $$ = new StatementNode( build_throw( $2 ) ); }
     
    12851305// If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex".
    12861306mutex_statement:
    1287         MUTEX '(' argument_expression_list ')' statement
     1307        MUTEX '(' argument_expression_list_opt ')' statement
    12881308                { SemanticError( yylloc, "Mutex statement is currently unimplemented." ); $$ = nullptr; }
    12891309        ;
     
    13021322        WAITFOR '(' cast_expression ')'
    13031323                { $$ = $3; }
    1304 //      | WAITFOR '(' cast_expression ',' argument_expression_list ')'
     1324//      | WAITFOR '(' cast_expression ',' argument_expression_list_opt ')'
    13051325//              { $$ = (ExpressionNode *)$3->set_last( $5 ); }
    1306         | WAITFOR '(' cast_expression_list ':' argument_expression_list ')'
     1326        | WAITFOR '(' cast_expression_list ':' argument_expression_list_opt ')'
    13071327                { $$ = (ExpressionNode *)($3->set_last( $5 )); }
    13081328        ;
     
    13111331        cast_expression
    13121332        | cast_expression_list ',' cast_expression
    1313                 { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     1333                // { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     1334                { SemanticError( yylloc, "List of mutex member is currently unimplemented." ); $$ = nullptr; }
    13141335        ;
    13151336
     
    13201341waitfor_clause:
    13211342        when_clause_opt waitfor statement                                       %prec THEN
    1322                 { $$ = build_waitfor( $2, $3, $1 ); }
     1343                { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1 ); }
    13231344        | when_clause_opt waitfor statement WOR waitfor_clause
    1324                 { $$ = build_waitfor( $2, $3, $1, $5 ); }
     1345                { $$ = build_waitfor( $2, maybe_build_compound( $3 ), $1, $5 ); }
    13251346        | when_clause_opt timeout statement                                     %prec THEN
    1326                 { $$ = build_waitfor_timeout( $2, $3, $1 ); }
     1347                { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1 ); }
    13271348        | when_clause_opt ELSE statement
    1328                 { $$ = build_waitfor_timeout( nullptr, $3, $1 ); }
     1349                { $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }
    13291350                // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    13301351        | when_clause_opt timeout statement WOR ELSE statement
    13311352                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    13321353        | when_clause_opt timeout statement WOR when_clause ELSE statement
    1333                 { $$ = build_waitfor_timeout( $2, $3, $1, $7, $5 ); }
     1354                { $$ = build_waitfor_timeout( $2, maybe_build_compound( $3 ), $1, maybe_build_compound( $7 ), $5 ); }
    13341355        ;
    13351356
     
    16541675
    16551676typedef_expression:
    1656                 // GCC, naming expression type: typedef name = exp; gives a name to the type of an expression
     1677                // deprecated GCC, naming expression type: typedef name = exp; gives a name to the type of an expression
    16571678        TYPEDEF identifier '=' assignment_expression
    16581679                {
    1659                         // $$ = DeclarationNode::newName( 0 );                  // unimplemented
    1660                         SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr;
     1680                        SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
    16611681                }
    16621682        | typedef_expression pop ',' push identifier '=' assignment_expression
    16631683                {
    1664                         // $$ = DeclarationNode::newName( 0 );                  // unimplemented
    1665                         SemanticError( yylloc, "Typedef expression is currently unimplemented." ); $$ = nullptr;
    1666                 }
    1667         ;
    1668 
    1669 //c_declaration:
    1670 //      declaring_list pop ';'
    1671 //      | typedef_declaration pop ';'
    1672 //      | typedef_expression pop ';'                                            // GCC, naming expression type
    1673 //      | sue_declaration_specifier pop ';'
    1674 //      ;
    1675 //
    1676 //declaring_list:
    1677 //              // A semantic check is required to ensure asm_name only appears on declarations with implicit or explicit static
    1678 //              // storage-class
    1679 //       declarator asm_name_opt initializer_opt
    1680 //              {
    1681 //                      typedefTable.addToEnclosingScope( IDENTIFIER );
    1682 //                      $$ = ( $2->addType( $1 ))->addAsmName( $3 )->addInitializer( $4 );
    1683 //              }
    1684 //      | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
    1685 //              {
    1686 //                      typedefTable.addToEnclosingScope( IDENTIFIER );
    1687 //                      $$ = $1->appendList( $1->cloneBaseType( $4->addAsmName( $5 )->addInitializer( $6 ) ) );
    1688 //              }
    1689 //      ;
     1684                        SemanticError( yylloc, "Typedef expression is deprecated, use typeof(...) instead." ); $$ = nullptr;
     1685                }
     1686        ;
    16901687
    16911688c_declaration:
     
    16931690                { $$ = distAttr( $1, $2 ); }
    16941691        | typedef_declaration
    1695         | typedef_expression                                                            // GCC, naming expression type
     1692        | typedef_expression                                                            // deprecated GCC, naming expression type
    16961693        | sue_declaration_specifier
    16971694        ;
     
    20722069                { yyy = true; $$ = AggregateDecl::Union; }
    20732070        | EXCEPTION                                                                                     // CFA
    2074                 { yyy = true; $$ = AggregateDecl::Exception; }
     2071                // { yyy = true; $$ = AggregateDecl::Exception; }
     2072                { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20752073        ;
    20762074
    20772075aggregate_control:                                                                              // CFA
    2078         GENERATOR
    2079                 { yyy = true; $$ = AggregateDecl::Coroutine; }
     2076        MONITOR
     2077                { yyy = true; $$ = AggregateDecl::Monitor; }
     2078        | MUTEX STRUCT
     2079                { yyy = true; $$ = AggregateDecl::Monitor; }
     2080        | GENERATOR
     2081                { yyy = true; $$ = AggregateDecl::Generator; }
     2082        | MUTEX GENERATOR
     2083                { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20802084        | COROUTINE
    20812085                { yyy = true; $$ = AggregateDecl::Coroutine; }
    2082         | MONITOR
    2083                 { yyy = true; $$ = AggregateDecl::Monitor; }
     2086        | MUTEX COROUTINE
     2087                { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20842088        | THREAD
    20852089                { yyy = true; $$ = AggregateDecl::Thread; }
     2090        | MUTEX THREAD
     2091                { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20862092        ;
    20872093
     
    24062412// Overloading: function, data, and operator identifiers may be overloaded.
    24072413//
    2408 // Type declarations: "type" is used to generate new types for declaring objects. Similarly, "dtype" is used for object
     2414// Type declarations: "otype" is used to generate new types for declaring objects. Similarly, "dtype" is used for object
    24092415//     and incomplete types, and "ftype" is used for function types. Type declarations with initializers provide
    24102416//     definitions of new types. Type declarations with storage class "extern" provide opaque types.
     
    24352441        type_class identifier_or_type_name
    24362442                { typedefTable.addToScope( *$2, TYPEDEFname, "9" ); }
    2437           type_initializer_opt assertion_list_opt
     2443        type_initializer_opt assertion_list_opt
    24382444                { $$ = DeclarationNode::newTypeParam( $1, $2 )->addTypeInitializer( $4 )->addAssertions( $5 ); }
    24392445        | type_specifier identifier_parameter_declarator
     
    24622468        assertion
    24632469        | assertion_list assertion
    2464                 { $$ = $1 ? $1->appendList( $2 ) : $2; }
     2470                { $$ = $1->appendList( $2 ); }
    24652471        ;
    24662472
     
    27492755        | attr_name
    27502756                { $$ = DeclarationNode::newAttribute( $1 ); }
    2751         | attr_name '(' argument_expression_list ')'
     2757        | attr_name '(' argument_expression_list_opt ')'
    27522758                { $$ = DeclarationNode::newAttribute( $1, $3 ); }
    27532759        ;
  • src/ResolvExpr/AdjustExprType.cc

    r3c64c668 r58fe85a  
    100100
    101101namespace {
    102         struct AdjustExprType_new final : public ast::WithShortCircuiting {
     102        class AdjustExprType_new final : public ast::WithShortCircuiting {
     103                const ast::SymbolTable & symtab;
     104        public:
    103105                const ast::TypeEnvironment & tenv;
    104                 const ast::SymbolTable & symtab;
    105106
    106107                AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    107                 : tenv( e ), symtab( syms ) {}
     108                : symtab( syms ), tenv( e ) {}
    108109
    109                 void premutate( const ast::VoidType * ) { visit_children = false; }
    110                 void premutate( const ast::BasicType * ) { visit_children = false; }
    111                 void premutate( const ast::PointerType * ) { visit_children = false; }
    112                 void premutate( const ast::ArrayType * ) { visit_children = false; }
    113                 void premutate( const ast::FunctionType * ) { visit_children = false; }
    114                 void premutate( const ast::StructInstType * ) { visit_children = false; }
    115                 void premutate( const ast::UnionInstType * ) { visit_children = false; }
    116                 void premutate( const ast::EnumInstType * ) { visit_children = false; }
    117                 void premutate( const ast::TraitInstType * ) { visit_children = false; }
    118                 void premutate( const ast::TypeInstType * ) { visit_children = false; }
    119                 void premutate( const ast::TupleType * ) { visit_children = false; }
    120                 void premutate( const ast::VarArgsType * ) { visit_children = false; }
    121                 void premutate( const ast::ZeroType * ) { visit_children = false; }
    122                 void premutate( const ast::OneType * ) { visit_children = false; }
     110                void previsit( const ast::VoidType * ) { visit_children = false; }
     111                void previsit( const ast::BasicType * ) { visit_children = false; }
     112                void previsit( const ast::PointerType * ) { visit_children = false; }
     113                void previsit( const ast::ArrayType * ) { visit_children = false; }
     114                void previsit( const ast::FunctionType * ) { visit_children = false; }
     115                void previsit( const ast::StructInstType * ) { visit_children = false; }
     116                void previsit( const ast::UnionInstType * ) { visit_children = false; }
     117                void previsit( const ast::EnumInstType * ) { visit_children = false; }
     118                void previsit( const ast::TraitInstType * ) { visit_children = false; }
     119                void previsit( const ast::TypeInstType * ) { visit_children = false; }
     120                void previsit( const ast::TupleType * ) { visit_children = false; }
     121                void previsit( const ast::VarArgsType * ) { visit_children = false; }
     122                void previsit( const ast::ZeroType * ) { visit_children = false; }
     123                void previsit( const ast::OneType * ) { visit_children = false; }
    123124
    124                 const ast::Type * postmutate( const ast::ArrayType * at ) {
     125                const ast::Type * postvisit( const ast::ArrayType * at ) {
    125126                        return new ast::PointerType{ at->base, at->qualifiers };
    126127                }
    127128
    128                 const ast::Type * postmutate( const ast::FunctionType * ft ) {
     129                const ast::Type * postvisit( const ast::FunctionType * ft ) {
    129130                        return new ast::PointerType{ ft };
    130131                }
    131132
    132                 const ast::Type * postmutate( const ast::TypeInstType * inst ) {
     133                const ast::Type * postvisit( const ast::TypeInstType * inst ) {
    133134                        // replace known function-type-variables with pointer-to-function
    134                         if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
     135                        if ( const ast::EqvClass * eqvClass = tenv.lookup( *inst ) ) {
    135136                                if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
    136137                                        return new ast::PointerType{ inst };
  • src/ResolvExpr/AlternativeFinder.cc

    r3c64c668 r58fe85a  
    131131
    132132        void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) {
    133                 Indenter indent = { indentAmt };
    134                 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
    135                         i->print( os, indent );
    136                         os << std::endl;
     133                std::vector<std::string> sorted;
     134                sorted.reserve(list.size());
     135                for(const auto & c : list) {
     136                        std::stringstream ss;
     137                        c.print( ss, indentAmt );
     138                        sorted.push_back(ss.str());
     139                }
     140
     141                std::sort(sorted.begin(), sorted.end());
     142
     143                for ( const auto & s : sorted ) {
     144                        os << s << std::endl;
    137145                }
    138146        }
     
    251259                        SemanticError( expr, "No reasonable alternatives for expression " );
    252260                }
    253                 if ( mode.satisfyAssns || mode.prune ) {
     261                if ( mode.prune ) {
    254262                        // trim candidates just to those where the assertions resolve
    255263                        // - necessary pre-requisite to pruning
     
    12161224                        unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
    12171225                                haveAssertions, openVars, indexer );
    1218                         Cost thisCost = castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(),
    1219                                 indexer, alt.env );
     1226                        Cost thisCost =
     1227                                castExpr->isGenerated
     1228                                ? conversionCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(),   indexer, alt.env )
     1229                                : castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(), indexer, alt.env );
    12201230                        PRINT(
    12211231                                std::cerr << "working on cast with result: " << castExpr->result << std::endl;
     
    16981708
    16991709                                // unification run for side-effects
    1700                                 unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer );
     1710                                bool canUnify = unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer );
     1711                                (void) canUnify;
    17011712                                // xxx - do some inspecting on this line... why isn't result bound to initAlt.type?
    17021713
    1703                                 Cost thisCost = castCost( alt.expr->result, toType, alt.expr->get_lvalue(),
     1714                                Cost thisCost = computeConversionCost( alt.expr->result, toType, alt.expr->get_lvalue(),
    17041715                                        indexer, newEnv );
     1716
     1717                                PRINT(
     1718                                        Cost legacyCost = castCost( alt.expr->result, toType, alt.expr->get_lvalue(),
     1719                                                indexer, newEnv );
     1720                                        std::cerr << "Considering initialization:";
     1721                                        std::cerr << std::endl << "  FROM: "; alt.expr->result->print(std::cerr);
     1722                                        std::cerr << std::endl << "  TO: ";   toType          ->print(std::cerr);
     1723                                        std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
     1724                                        std::cerr << std::endl << "  Legacy cost " << legacyCost;
     1725                                        std::cerr << std::endl << "  New cost " << thisCost;
     1726                                        std::cerr << std::endl;
     1727                                )
     1728
    17051729                                if ( thisCost != Cost::infinity ) {
    17061730                                        // count one safe conversion for each value that is thrown away
  • src/ResolvExpr/Candidate.cpp

    r3c64c668 r58fe85a  
    4141
    4242void print( std::ostream & os, const CandidateList & cands, Indenter indent ) {
    43         for ( const CandidateRef & cand : cands ) {
    44                 print( os, *cand, indent );
    45                 os << std::endl;
     43        std::vector<std::string> sorted;
     44        sorted.reserve(cands.size());
     45        for(const auto & c : cands) {
     46                std::stringstream ss;
     47                print( ss, *c, indent );
     48                sorted.push_back(ss.str());
     49        }
     50
     51        std::sort(sorted.begin(), sorted.end());
     52
     53        for ( const auto & s : sorted ) {
     54                os << s << std::endl;
    4655        }
    4756}
  • src/ResolvExpr/Candidate.hpp

    r3c64c668 r58fe85a  
    5151
    5252        Candidate( const ast::Expr * x, const ast::TypeEnvironment & e )
    53         : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {}
     53        : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {
     54                assert(x->result);
     55        }
    5456
    5557        Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero )
    5658        : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
    57           need( o.need ) {}
     59          need( o.need ) {
     60                assert(x->result);
     61        }
    5862
    5963        Candidate(
    60                 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
     64                const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
    6165                const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero )
    62         : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {}
     66        : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {
     67                assert(x->result);
     68        }
    6369
    6470        Candidate(
     
    6672                ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero )
    6773        : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ),
    68           need( n.begin(), n.end() ) {}
     74          need( n.begin(), n.end() ) {
     75                assert(x->result);
     76        }
    6977};
    7078
  • src/ResolvExpr/CandidateFinder.cpp

    r3c64c668 r58fe85a  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Wed Jun 5 14:30:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct  1 14:55:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    4343#include "SymTab/Validate.h"      // for validateType
    4444#include "Tuples/Tuples.h"        // for handleTupleAssignment
     45#include "InitTweak/InitTweak.h"  // for getPointerBase
     46
     47#include "Common/Stats/Counter.h"
    4548
    4649#define PRINT( text ) if ( resolvep ) { text }
     
    5457                return new ast::CastExpr{ expr, expr->result->stripReferences() };
    5558        }
    56        
     59
    5760        return expr;
    5861}
     
    6164UniqueId globalResnSlot = 0;
    6265
    63 Cost computeConversionCost( 
    64         const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
    65         const ast::TypeEnvironment & env
     66Cost computeConversionCost(
     67        const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
     68        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    6669) {
    6770        PRINT(
     
    7477                std::cerr << std::endl;
    7578        )
    76         Cost convCost = conversionCost( argType, paramType, symtab, env );
     79        Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env );
    7780        PRINT(
    7881                std::cerr << std::endl << "cost is " << convCost << std::endl;
     
    107110
    108111        /// Computes conversion cost for a given expression to a given type
    109         const ast::Expr * computeExpressionConversionCost( 
    110                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 
     112        const ast::Expr * computeExpressionConversionCost(
     113                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
    111114        ) {
    112                 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env );
     115                Cost convCost = computeConversionCost(
     116                                arg->result, paramType, arg->get_lvalue(), symtab, env );
    113117                outCost += convCost;
    114118
    115                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 
    116                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 
     119                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
     120                // conversion. Ignore poly cost for now, since this requires resolution of the cast to
    117121                // infer parameters and this does not currently work for the reason stated below
    118122                Cost tmpCost = convCost;
     
    123127                        return new ast::CastExpr{ arg, newType };
    124128
    125                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not 
    126                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 
     129                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     130                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
    127131                        // once this is fixed it should be possible to resolve the cast.
    128                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 
    129                         // but it shouldn't be because this makes the conversion from DT* to DT* since 
     132                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
     133                        // but it shouldn't be because this makes the conversion from DT* to DT* since
    130134                        // commontype(zero_t, DT*) is DT*, rather than nothing
    131135
    132136                        // CandidateFinder finder{ symtab, env };
    133137                        // finder.find( arg, ResolvMode::withAdjustment() );
    134                         // assertf( finder.candidates.size() > 0, 
     138                        // assertf( finder.candidates.size() > 0,
    135139                        //      "Somehow castable expression failed to find alternatives." );
    136                         // assertf( finder.candidates.size() == 1, 
     140                        // assertf( finder.candidates.size() == 1,
    137141                        //      "Somehow got multiple alternatives for known cast expression." );
    138142                        // return finder.candidates.front()->expr;
     
    143147
    144148        /// Computes conversion cost for a given candidate
    145         Cost computeApplicationConversionCost( 
    146                 CandidateRef cand, const ast::SymbolTable & symtab 
     149        Cost computeApplicationConversionCost(
     150                CandidateRef cand, const ast::SymbolTable & symtab
    147151        ) {
    148152                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     
    167171                                if ( function->isVarArgs ) {
    168172                                        convCost.incUnsafe();
    169                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 
     173                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
    170174                                                << convCost << std::endl; ; )
    171175                                        // convert reference-typed expressions into value-typed expressions
    172                                         cand->expr = ast::mutate_field_index( 
    173                                                 appExpr, &ast::ApplicationExpr::args, i, 
     176                                        cand->expr = ast::mutate_field_index(
     177                                                appExpr, &ast::ApplicationExpr::args, i,
    174178                                                referenceToRvalueConversion( args[i], convCost ) );
    175179                                        continue;
     
    180184                                // Default arguments should be free - don't include conversion cost.
    181185                                // Unwrap them here because they are not relevant to the rest of the system
    182                                 cand->expr = ast::mutate_field_index( 
     186                                cand->expr = ast::mutate_field_index(
    183187                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
    184188                                ++param;
     
    187191
    188192                        // mark conversion cost and also specialization cost of param type
    189                         const ast::Type * paramType = (*param)->get_type();
    190                         cand->expr = ast::mutate_field_index( 
    191                                 appExpr, &ast::ApplicationExpr::args, i, 
    192                                 computeExpressionConversionCost( 
    193                                         args[i], paramType, symtab, cand->env, convCost ) );
    194                         convCost.decSpec( specCost( paramType ) );
     193                        // const ast::Type * paramType = (*param)->get_type();
     194                        cand->expr = ast::mutate_field_index(
     195                                appExpr, &ast::ApplicationExpr::args, i,
     196                                computeExpressionConversionCost(
     197                                        args[i], *param, symtab, cand->env, convCost ) );
     198                        convCost.decSpec( specCost( *param ) );
    195199                        ++param;  // can't be in for-loop update because of the continue
    196200                }
     
    198202                if ( param != params.end() ) return Cost::infinity;
    199203
    200                 // specialization cost of return types can't be accounted for directly, it disables 
     204                // specialization cost of return types can't be accounted for directly, it disables
    201205                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    202206                //
     
    208212                // mark type variable and specialization cost of forall clause
    209213                convCost.incVar( function->forall.size() );
    210                 for ( const ast::TypeDecl * td : function->forall ) {
    211                         convCost.decSpec( td->assertions.size() );
    212                 }
     214                convCost.decSpec( function->assertions.size() );
    213215
    214216                return convCost;
    215217        }
    216218
    217         void makeUnifiableVars( 
    218                 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
    219                 ast::AssertionSet & need 
     219        void makeUnifiableVars(
     220                const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
     221                ast::AssertionSet & need
    220222        ) {
    221                 for ( const ast::TypeDecl * tyvar : type->forall ) {
    222                         unifiableVars[ tyvar->name ] = ast::TypeDecl::Data{ tyvar };
    223                         for ( const ast::DeclWithType * assn : tyvar->assertions ) {
    224                                 need[ assn ].isUsed = true;
    225                         }
     223                for ( auto & tyvar : type->forall ) {
     224                        unifiableVars[ *tyvar ] = ast::TypeDecl::Data{ tyvar->base };
     225                }
     226                for ( auto & assn : type->assertions ) {
     227                        need[ assn ].isUsed = true;
    226228                }
    227229        }
     
    254256
    255257                ArgPack()
    256                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 
     258                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
    257259                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    258                
    259                 ArgPack( 
    260                         const ast::TypeEnvironment & env, const ast::AssertionSet & need, 
     260
     261                ArgPack(
     262                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    261263                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
    262                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 
     264                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    263265                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    264                
     266
    265267                ArgPack(
    266                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 
    267                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 
    268                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 
     268                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     269                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     270                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    269271                        unsigned nextExpl = 0, unsigned explAlt = 0 )
    270272                : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ),
    271273                  have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    272274                  nextExpl( nextExpl ), explAlt( explAlt ) {}
    273                
     275
    274276                ArgPack(
    275                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 
     277                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
    276278                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    277                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 
    278                   need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 
     279                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),
     280                  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ),
    279281                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    280                
     282
    281283                /// true if this pack is in the middle of an exploded argument
    282284                bool hasExpl() const { return nextExpl > 0; }
     
    286288                        return args[ nextArg-1 ][ explAlt ];
    287289                }
    288                
     290
    289291                /// Ends a tuple expression, consolidating the appropriate args
    290292                void endTuple( const std::vector< ArgPack > & packs ) {
     
    307309
    308310        /// Instantiates an argument to match a parameter, returns false if no matching results left
    309         bool instantiateArgument( 
    310                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 
    311                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 
    312                 unsigned nTuples = 0 
     311        bool instantiateArgument(
     312                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
     313                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
     314                unsigned nTuples = 0
    313315        ) {
    314316                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     
    318320                                // xxx - dropping initializer changes behaviour from previous, but seems correct
    319321                                // ^^^ need to handle the case where a tuple has a default argument
    320                                 if ( ! instantiateArgument( 
     322                                if ( ! instantiateArgument(
    321323                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    322324                                nTuples = 0;
     
    329331                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    330332                        // paramType is a ttype, consumes all remaining arguments
    331                        
     333
    332334                        // completed tuples; will be spliced to end of results to finish
    333335                        std::vector< ArgPack > finalResults{};
     
    342344                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
    343345                                        unsigned nextArg = results[i].nextArg;
    344                                        
     346
    345347                                        // use next element of exploded tuple if present
    346348                                        if ( results[i].hasExpl() ) {
     
    352354                                                results.emplace_back(
    353355                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    354                                                         copy( results[i].need ), copy( results[i].have ), 
     356                                                        copy( results[i].need ), copy( results[i].have ),
    355357                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    356358                                                        results[i].explAlt );
     
    370372                                                        // push empty tuple expression
    371373                                                        newResult.parent = i;
    372                                                         std::vector< ast::ptr< ast::Expr > > emptyList;
    373                                                         newResult.expr =
    374                                                                 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) };
     374                                                        newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
    375375                                                        argType = newResult.expr->result;
    376376                                                } else {
     
    400400
    401401                                                // check unification for ttype before adding to final
    402                                                 if ( 
    403                                                         unify( 
     402                                                if (
     403                                                        unify(
    404404                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
    405                                                                 newResult.open, symtab ) 
     405                                                                newResult.open, symtab )
    406406                                                ) {
    407407                                                        finalResults.emplace_back( move( newResult ) );
     
    424424                                                if ( expl.exprs.empty() ) {
    425425                                                        results.emplace_back(
    426                                                                 results[i], move( env ), copy( results[i].need ), 
     426                                                                results[i], move( env ), copy( results[i].need ),
    427427                                                                copy( results[i].have ), move( open ), nextArg + 1, expl.cost );
    428                                                        
     428
    429429                                                        continue;
    430430                                                }
     
    432432                                                // add new result
    433433                                                results.emplace_back(
    434                                                         i, expl.exprs.front(), move( env ), copy( results[i].need ), 
    435                                                         copy( results[i].have ), move( open ), nextArg + 1, nTuples, 
     434                                                        i, expl.exprs.front(), move( env ), copy( results[i].need ),
     435                                                        copy( results[i].have ), move( open ), nextArg + 1, nTuples,
    436436                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    437437                                        }
     
    479479
    480480                                        results.emplace_back(
    481                                                 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 
     481                                                i, expr, move( env ), move( need ), move( have ), move( open ), nextArg,
    482482                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
    483483                                }
     
    495495                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    496496                                                results.emplace_back(
    497                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 
     497                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),
    498498                                                        move( need ), move( have ), move( open ), nextArg, nTuples );
    499499                                        }
     
    517517                                if ( expl.exprs.empty() ) {
    518518                                        results.emplace_back(
    519                                                 results[i], move( env ), move( need ), move( have ), move( open ), 
     519                                                results[i], move( env ), move( need ), move( have ), move( open ),
    520520                                                nextArg + 1, expl.cost );
    521                                        
     521
    522522                                        continue;
    523523                                }
     
    539539                                        // add new result
    540540                                        results.emplace_back(
    541                                                 i, expr, move( env ), move( need ), move( have ), move( open ), 
     541                                                i, expr, move( env ), move( need ), move( have ), move( open ),
    542542                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    543543                                }
     
    548548                genStart = genEnd;
    549549
    550                 return genEnd != results.size();
     550                return genEnd != results.size();  // were any new results added?
    551551        }
    552552
    553553        /// Generate a cast expression from `arg` to `toType`
    554         const ast::Expr * restructureCast( 
     554        const ast::Expr * restructureCast(
    555555                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    556556        ) {
    557                 if ( 
    558                         arg->result->size() > 1 
    559                         && ! toType->isVoid() 
    560                         && ! dynamic_cast< const ast::ReferenceType * >( toType ) 
     557                if (
     558                        arg->result->size() > 1
     559                        && ! toType->isVoid()
     560                        && ! dynamic_cast< const ast::ReferenceType * >( toType )
    561561                ) {
    562                         // Argument is a tuple and the target type is neither void nor a reference. Cast each 
    563                         // member of the tuple to its corresponding target type, producing the tuple of those 
    564                         // cast expressions. If there are more components of the tuple than components in the 
    565                         // target type, then excess components do not come out in the result expression (but 
     562                        // Argument is a tuple and the target type is neither void nor a reference. Cast each
     563                        // member of the tuple to its corresponding target type, producing the tuple of those
     564                        // cast expressions. If there are more components of the tuple than components in the
     565                        // target type, then excess components do not come out in the result expression (but
    566566                        // UniqueExpr ensures that the side effects will still be produced)
    567567                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    568                                 // expressions which may contain side effects require a single unique instance of 
     568                                // expressions which may contain side effects require a single unique instance of
    569569                                // the expression
    570570                                arg = new ast::UniqueExpr{ arg->location, arg };
     
    574574                                // cast each component
    575575                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    576                                 components.emplace_back( 
     576                                components.emplace_back(
    577577                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    578578                        }
     
    594594
    595595        /// Actually visits expressions to find their candidate interpretations
    596         struct Finder final : public ast::WithShortCircuiting {
     596        class Finder final : public ast::WithShortCircuiting {
     597                const ast::SymbolTable & symtab;
     598        public:
     599                static size_t traceId;
    597600                CandidateFinder & selfFinder;
    598                 const ast::SymbolTable & symtab;
    599601                CandidateList & candidates;
    600602                const ast::TypeEnvironment & tenv;
    601603                ast::ptr< ast::Type > & targetType;
    602604
     605                enum Errors {
     606                        NotFound,
     607                        NoMatch,
     608                        ArgsToFew,
     609                        ArgsToMany,
     610                        RetsToFew,
     611                        RetsToMany,
     612                        NoReason
     613                };
     614
     615                struct {
     616                        Errors code = NotFound;
     617                } reason;
     618
    603619                Finder( CandidateFinder & f )
    604                 : selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),
     620                : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),
    605621                  targetType( f.targetType ) {}
    606                
     622
    607623                void previsit( const ast::Node * ) { visit_children = false; }
    608624
     
    611627                void addCandidate( Args &&... args ) {
    612628                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
     629                        reason.code = NoReason;
    613630                }
    614631
     
    639656
    640657                /// Completes a function candidate with arguments located
    641                 void validateFunctionCandidate( 
    642                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 
    643                         CandidateList & out 
     658                void validateFunctionCandidate(
     659                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     660                        CandidateList & out
    644661                ) {
    645                         ast::ApplicationExpr * appExpr = 
     662                        ast::ApplicationExpr * appExpr =
    646663                                new ast::ApplicationExpr{ func->expr->location, func->expr };
    647664                        // sum cost and accumulate arguments
     
    657674                        appExpr->args = move( vargs );
    658675                        // build and validate new candidate
    659                         auto newCand = 
     676                        auto newCand =
    660677                                std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    661678                        PRINT(
     
    669686                /// Builds a list of candidates for a function, storing them in out
    670687                void makeFunctionCandidates(
    671                         const CandidateRef & func, const ast::FunctionType * funcType, 
     688                        const CandidateRef & func, const ast::FunctionType * funcType,
    672689                        const ExplodedArgs_new & args, CandidateList & out
    673690                ) {
     
    676693                        ast::TypeEnvironment funcEnv{ func->env };
    677694                        makeUnifiableVars( funcType, funcOpen, funcNeed );
    678                         // add all type variables as open variables now so that those not used in the parameter
    679                         // list are still considered open
     695                        // add all type variables as open variables now so that those not used in the
     696                        // parameter list are still considered open
    680697                        funcEnv.add( funcType->forall );
    681698
    682699                        if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
    683700                                // attempt to narrow based on expected target type
    684                                 const ast::Type * returnType = funcType->returns.front()->get_type();
    685                                 if ( ! unify( 
    686                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 
     701                                const ast::Type * returnType = funcType->returns.front();
     702                                if ( ! unify(
     703                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
    687704                                ) {
    688705                                        // unification failed, do not pursue this candidate
     
    696713                        std::size_t genStart = 0;
    697714
    698                         for ( const ast::DeclWithType * param : funcType->params ) {
    699                                 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param );
    700                                 // Try adding the arguments corresponding to the current parameter to the existing
     715                        // xxx - how to handle default arg after change to ftype representation?
     716                        if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
     717                                if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
     718                                        // function may have default args only if directly calling by name
     719                                        // must use types on candidate however, due to RenameVars substitution
     720                                        auto nParams = funcType->params.size();
     721
     722                                        for (size_t i=0; i<nParams; ++i) {
     723                                                auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
     724                                                if (!instantiateArgument(
     725                                                        funcType->params[i], obj->init, args, results, genStart, symtab)) return;
     726                                        }
     727                                        goto endMatch;
     728                                }
     729                        }
     730                        for ( const auto & param : funcType->params ) {
     731                                // Try adding the arguments corresponding to the current parameter to the existing
    701732                                // matches
    702                                 if ( ! instantiateArgument(
    703                                         obj->type, obj->init, args, results, genStart, symtab ) ) return;
    704                         }
    705 
     733                                // no default args for indirect calls
     734                                if ( ! instantiateArgument(
     735                                        param, nullptr, args, results, genStart, symtab ) ) return;
     736                        }
     737
     738                        endMatch:
    706739                        if ( funcType->isVarArgs ) {
    707740                                // append any unused arguments to vararg pack
     
    750783                                                        if ( expl.exprs.empty() ) {
    751784                                                                results.emplace_back(
    752                                                                         results[i], move( env ), copy( results[i].need ), 
    753                                                                         copy( results[i].have ), move( open ), nextArg + 1, 
     785                                                                        results[i], move( env ), copy( results[i].need ),
     786                                                                        copy( results[i].have ), move( open ), nextArg + 1,
    754787                                                                        expl.cost );
    755788
     
    760793                                                        results.emplace_back(
    761794                                                                i, expl.exprs.front(), move( env ), copy( results[i].need ),
    762                                                                 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 
     795                                                                copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost,
    763796                                                                expl.exprs.size() == 1 ? 0 : 1, j );
    764797                                                }
     
    780813                /// Adds implicit struct-conversions to the alternative list
    781814                void addAnonConversions( const CandidateRef & cand ) {
    782                         // adds anonymous member interpretations whenever an aggregate value type is seen. 
    783                         // it's okay for the aggregate expression to have reference type -- cast it to the 
     815                        // adds anonymous member interpretations whenever an aggregate value type is seen.
     816                        // it's okay for the aggregate expression to have reference type -- cast it to the
    784817                        // base type to treat the aggregate as the referenced value
    785818                        ast::ptr< ast::Expr > aggrExpr( cand->expr );
    786819                        ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    787820                        cand->env.apply( aggrType );
    788                        
     821
    789822                        if ( aggrType.as< ast::ReferenceType >() ) {
    790823                                aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     
    799832
    800833                /// Adds aggregate member interpretations
    801                 void addAggMembers( 
    802                         const ast::ReferenceToType * aggrInst, const ast::Expr * expr,
    803                         const Candidate & cand, const Cost & addedCost, const std::string & name 
     834                void addAggMembers(
     835                        const ast::BaseInstType * aggrInst, const ast::Expr * expr,
     836                        const Candidate & cand, const Cost & addedCost, const std::string & name
    804837                ) {
    805838                        for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    806839                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    807                                 CandidateRef newCand = std::make_shared<Candidate>( 
     840                                CandidateRef newCand = std::make_shared<Candidate>(
    808841                                        cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    809                                 // add anonymous member interpretations whenever an aggregate value type is seen 
     842                                // add anonymous member interpretations whenever an aggregate value type is seen
    810843                                // as a member expression
    811844                                addAnonConversions( newCand );
     
    815848
    816849                /// Adds tuple member interpretations
    817                 void addTupleMembers( 
    818                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 
    819                         const Cost & addedCost, const ast::Expr * member 
     850                void addTupleMembers(
     851                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     852                        const Cost & addedCost, const ast::Expr * member
    820853                ) {
    821854                        if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    822                                 // get the value of the constant expression as an int, must be between 0 and the 
     855                                // get the value of the constant expression as an int, must be between 0 and the
    823856                                // length of the tuple to have meaning
    824857                                long long val = constantExpr->intValue();
    825858                                if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    826859                                        addCandidate(
    827                                                 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 
     860                                                cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
    828861                                                addedCost );
    829862                                }
     
    832865
    833866                void postvisit( const ast::UntypedExpr * untypedExpr ) {
    834                         CandidateFinder funcFinder{ symtab, tenv };
    835                         funcFinder.find( untypedExpr->func, ResolvMode::withAdjustment() );
    836                         // short-circuit if no candidates
    837                         if ( funcFinder.candidates.empty() ) return;
    838 
    839                         std::vector< CandidateFinder > argCandidates =
     867                        std::vector< CandidateFinder > argCandidates =
    840868                                selfFinder.findSubExprs( untypedExpr->args );
    841                        
     869
    842870                        // take care of possible tuple assignments
    843871                        // if not tuple assignment, handled as normal function call
    844872                        Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
     873
     874                        CandidateFinder funcFinder{ symtab, tenv };
     875                        if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
     876                                auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     877                                if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
     878                                        assertf(!argCandidates.empty(), "special function call without argument");
     879                                        for (auto & firstArgCand: argCandidates[0]) {
     880                                                ast::ptr<ast::Type> argType = firstArgCand->expr->result;
     881                                                firstArgCand->env.apply(argType);
     882                                                // strip references
     883                                                // xxx - is this correct?
     884                                                while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
     885
     886                                                // convert 1-tuple to plain type
     887                                                if (auto tuple = argType.as<ast::TupleType>()) {
     888                                                        if (tuple->size() == 1) {
     889                                                                argType = tuple->types[0];
     890                                                        }
     891                                                }
     892                                               
     893                                                // if argType is an unbound type parameter, all special functions need to be searched.
     894                                                if (isUnboundType(argType)) {
     895                                                        funcFinder.otypeKeys.clear();
     896                                                        break;
     897                                                }
     898
     899                                                if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);
     900                                                else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
     901                                        }
     902                                }
     903                        }
     904                        // if candidates are already produced, do not fail
     905                        // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
     906                        // this means there exists ctor/assign functions with a tuple as first parameter.
     907                        ResolvMode mode = {
     908                                true, // adjust
     909                                !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
     910                                selfFinder.candidates.empty() // failfast if other options are not found
     911                        };
     912                        funcFinder.find( untypedExpr->func, mode );
     913                        // short-circuit if no candidates
     914                        // if ( funcFinder.candidates.empty() ) return;
     915
     916                        reason.code = NoMatch;
    845917
    846918                        // find function operators
     
    877949                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    878950                                                        CandidateRef newFunc{ new Candidate{ *func } };
    879                                                         newFunc->expr = 
     951                                                        newFunc->expr =
    880952                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    881953                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
    882954                                                }
    883                                         } else if ( 
    884                                                 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 
     955                                        } else if (
     956                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
    885957                                        ) {
    886                                                 if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
     958                                                if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
    887959                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    888960                                                                CandidateRef newFunc{ new Candidate{ *func } };
    889                                                                 newFunc->expr = 
     961                                                                newFunc->expr =
    890962                                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    891963                                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     
    901973                                std::vector< ExplodedArg > funcE;
    902974                                funcE.reserve( funcFinder.candidates.size() );
    903                                 for ( const CandidateRef & func : funcFinder ) { 
     975                                for ( const CandidateRef & func : funcFinder ) {
    904976                                        funcE.emplace_back( *func, symtab );
    905977                                }
     
    913985                                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    914986                                                                CandidateRef newOp{ new Candidate{ *op} };
    915                                                                 newOp->expr = 
     987                                                                newOp->expr =
    916988                                                                        referenceToRvalueConversion( newOp->expr, newOp->cost );
    917989                                                                makeFunctionCandidates( newOp, function, argExpansions, found );
     
    922994                        }
    923995
    924                         // Implement SFINAE; resolution errors are only errors if there aren't any non-error 
     996                        // Implement SFINAE; resolution errors are only errors if there aren't any non-error
    925997                        // candidates
    926998                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     
    9341006                                        auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    9351007                                        auto function = pointer->base.strict_as< ast::FunctionType >();
    936                                        
     1008
    9371009                                        std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    9381010                                        std::cerr << "parameters are:" << std::endl;
     
    9571029                        promoteCvtCost( winners );
    9581030
    959                         // function may return a struct/union value, in which case we need to add candidates 
    960                         // for implicit conversions to each of the anonymous members, which must happen after 
     1031                        // function may return a struct/union value, in which case we need to add candidates
     1032                        // for implicit conversions to each of the anonymous members, which must happen after
    9611033                        // `findMinCost`, since anon conversions are never the cheapest
    9621034                        for ( const CandidateRef & c : winners ) {
     
    9661038
    9671039                        if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    968                                 // If resolution is unsuccessful with a target type, try again without, since it 
     1040                                // If resolution is unsuccessful with a target type, try again without, since it
    9691041                                // will sometimes succeed when it wouldn't with a target type binding.
    9701042                                // For example:
     
    9831055                /// true if expression is an lvalue
    9841056                static bool isLvalue( const ast::Expr * x ) {
    985                         return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() );
     1057                        return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
    9861058                }
    9871059
     
    9891061                        CandidateFinder finder{ symtab, tenv };
    9901062                        finder.find( addressExpr->arg );
     1063
     1064                        if( finder.candidates.empty() ) return;
     1065
     1066                        reason.code = NoMatch;
     1067
    9911068                        for ( CandidateRef & r : finder.candidates ) {
    9921069                                if ( ! isLvalue( r->expr ) ) continue;
     
    10031080                        assert( toType );
    10041081                        toType = resolveTypeof( toType, symtab );
    1005                         toType = SymTab::validateType( castExpr->location, toType, symtab );
     1082                        // toType = SymTab::validateType( castExpr->location, toType, symtab );
    10061083                        toType = adjustExprType( toType, tenv, symtab );
    10071084
    10081085                        CandidateFinder finder{ symtab, tenv, toType };
    10091086                        finder.find( castExpr->arg, ResolvMode::withAdjustment() );
     1087
     1088                        if( !finder.candidates.empty() ) reason.code = NoMatch;
    10101089
    10111090                        CandidateList matches;
     
    10161095                                cand->env.extractOpenVars( open );
    10171096
    1018                                 // It is possible that a cast can throw away some values in a multiply-valued 
    1019                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 
    1020                                 // subexpression results that are cast directly. The candidate is invalid if it 
     1097                                // It is possible that a cast can throw away some values in a multiply-valued
     1098                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
     1099                                // subexpression results that are cast directly. The candidate is invalid if it
    10211100                                // has fewer results than there are types to cast to.
    10221101                                int discardedValues = cand->expr->result->size() - toType->size();
     
    10251104                                // unification run for side-effects
    10261105                                unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1027                                 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env );
     1106                                Cost thisCost =
     1107                                        (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
     1108                            ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
     1109                            : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
     1110
    10281111                                PRINT(
    10291112                                        std::cerr << "working on cast with result: " << toType << std::endl;
     
    10371120                                        // count one safe conversion for each value that is thrown away
    10381121                                        thisCost.incSafe( discardedValues );
    1039                                         CandidateRef newCand = std::make_shared<Candidate>( 
    1040                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ), 
    1041                                                 copy( cand->env ), move( open ), move( need ), cand->cost, 
     1122                                        CandidateRef newCand = std::make_shared<Candidate>(
     1123                                                restructureCast( cand->expr, toType, castExpr->isGenerated ),
     1124                                                copy( cand->env ), move( open ), move( need ), cand->cost,
    10421125                                                cand->cost + thisCost );
    10431126                                        inferParameters( newCand, matches );
     
    10571140                        finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    10581141                        for ( CandidateRef & r : finder.candidates ) {
    1059                                 addCandidate( 
    1060                                         *r, 
     1142                                addCandidate(
     1143                                        *r,
    10611144                                        new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    10621145                        }
     1146                }
     1147
     1148                void postvisit( const ast::KeywordCastExpr * castExpr ) {
     1149                        const auto & loc = castExpr->location;
     1150                        assertf( castExpr->result, "Cast target should have been set in Validate." );
     1151                        auto ref = castExpr->result.strict_as<ast::ReferenceType>();
     1152                        auto inst = ref->base.strict_as<ast::StructInstType>();
     1153                        auto target = inst->base.get();
     1154
     1155                        CandidateFinder finder{ symtab, tenv };
     1156
     1157                        auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
     1158                                for(auto & cand : found) {
     1159                                        const ast::Type * expr = cand->expr->result.get();
     1160                                        if(expect_ref) {
     1161                                                auto res = dynamic_cast<const ast::ReferenceType*>(expr);
     1162                                                if(!res) { continue; }
     1163                                                expr = res->base.get();
     1164                                        }
     1165
     1166                                        if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
     1167                                                auto td = cand->env.lookup(*insttype);
     1168                                                if(!td) { continue; }
     1169                                                expr = td->bound.get();
     1170                                        }
     1171
     1172                                        if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
     1173                                                if(base->base == target) {
     1174                                                        candidates.push_back( std::move(cand) );
     1175                                                        reason.code = NoReason;
     1176                                                }
     1177                                        }
     1178                                }
     1179                        };
     1180
     1181                        try {
     1182                                // Attempt 1 : turn (thread&)X into ($thread&)X.__thrd
     1183                                // Clone is purely for memory management
     1184                                std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
     1185
     1186                                // don't prune here, since it's guaranteed all alternatives will have the same type
     1187                                finder.find( tech1.get(), ResolvMode::withoutPrune() );
     1188                                pick_alternatives(finder.candidates, false);
     1189
     1190                                return;
     1191                        } catch(SemanticErrorException & ) {}
     1192
     1193                        // Fallback : turn (thread&)X into ($thread&)get_thread(X)
     1194                        std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
     1195                        // don't prune here, since it's guaranteed all alternatives will have the same type
     1196                        finder.find( fallback.get(), ResolvMode::withoutPrune() );
     1197
     1198                        pick_alternatives(finder.candidates, true);
     1199
     1200                        // Whatever happens here, we have no more fallbacks
    10631201                }
    10641202
     
    10671205                        aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    10681206                        for ( CandidateRef & agg : aggFinder.candidates ) {
    1069                                 // it's okay for the aggregate expression to have reference type -- cast it to the 
     1207                                // it's okay for the aggregate expression to have reference type -- cast it to the
    10701208                                // base type to treat the aggregate as the referenced value
    10711209                                Cost addedCost = Cost::zero;
     
    10741212                                // find member of the given type
    10751213                                if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1076                                         addAggMembers( 
     1214                                        addAggMembers(
    10771215                                                structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    10781216                                } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1079                                         addAggMembers( 
     1217                                        addAggMembers(
    10801218                                                unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    10811219                                } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     
    10901228
    10911229                void postvisit( const ast::NameExpr * nameExpr ) {
    1092                         std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name );
     1230                        std::vector< ast::SymbolTable::IdData > declList;
     1231                        if (!selfFinder.otypeKeys.empty()) {
     1232                                auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     1233                                assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
     1234
     1235                                for (auto & otypeKey: selfFinder.otypeKeys) {
     1236                                        auto result = symtab.specialLookupId(kind, otypeKey);
     1237                                        declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
     1238                                }
     1239                        }
     1240                        else {
     1241                                declList = symtab.lookupId( nameExpr->name );
     1242                        }
    10931243                        PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
     1244
     1245                        if( declList.empty() ) return;
     1246
     1247                        reason.code = NoMatch;
     1248
    10941249                        for ( auto & data : declList ) {
    10951250                                Cost cost = Cost::zero;
     
    10971252
    10981253                                CandidateRef newCand = std::make_shared<Candidate>(
    1099                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 
     1254                                        newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
    11001255                                        cost );
    11011256                                PRINT(
     
    11071262                                        std::cerr << std::endl;
    11081263                                )
    1109                                 newCand->expr = ast::mutate_field( 
    1110                                         newCand->expr.get(), &ast::Expr::result, 
     1264                                newCand->expr = ast::mutate_field(
     1265                                        newCand->expr.get(), &ast::Expr::result,
    11111266                                        renameTyVars( newCand->expr->result ) );
    1112                                 // add anonymous member interpretations whenever an aggregate value type is seen 
     1267                                // add anonymous member interpretations whenever an aggregate value type is seen
    11131268                                // as a name expression
    11141269                                addAnonConversions( newCand );
     
    11201275                        // not sufficient to just pass `variableExpr` here, type might have changed since
    11211276                        // creation
    1122                         addCandidate( 
     1277                        addCandidate(
    11231278                                new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    11241279                }
     
    11301285                void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    11311286                        if ( sizeofExpr->type ) {
    1132                                 addCandidate( 
    1133                                         new ast::SizeofExpr{ 
    1134                                                 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 
     1287                                addCandidate(
     1288                                        new ast::SizeofExpr{
     1289                                                sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) },
    11351290                                        tenv );
    11361291                        } else {
     
    11411296                                CandidateList winners = findMinCost( finder.candidates );
    11421297                                if ( winners.size() != 1 ) {
    1143                                         SemanticError( 
     1298                                        SemanticError(
    11441299                                                sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    11451300                                }
     
    11541309                void postvisit( const ast::AlignofExpr * alignofExpr ) {
    11551310                        if ( alignofExpr->type ) {
    1156                                 addCandidate( 
    1157                                         new ast::AlignofExpr{ 
    1158                                                 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 
     1311                                addCandidate(
     1312                                        new ast::AlignofExpr{
     1313                                                alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) },
    11591314                                        tenv );
    11601315                        } else {
     
    11651320                                CandidateList winners = findMinCost( finder.candidates );
    11661321                                if ( winners.size() != 1 ) {
    1167                                         SemanticError( 
     1322                                        SemanticError(
    11681323                                                alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    11691324                                }
     
    11721327                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    11731328                                choice->cost = Cost::zero;
    1174                                 addCandidate( 
     1329                                addCandidate(
    11751330                                        *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    11761331                        }
     
    11781333
    11791334                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
    1180                         const ast::ReferenceToType * aggInst;
     1335                        const ast::BaseInstType * aggInst;
    11811336                        if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
    11821337                        else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
     
    11851340                        for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    11861341                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1187                                 addCandidate( 
     1342                                addCandidate(
    11881343                                        new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    11891344                        }
     
    12061361                        finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    12071362                        if ( finder2.candidates.empty() ) return;
     1363
     1364                        reason.code = NoMatch;
    12081365
    12091366                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    12181375
    12191376                                        addCandidate(
    1220                                                 new ast::LogicalExpr{ 
     1377                                                new ast::LogicalExpr{
    12211378                                                        logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    12221379                                                move( env ), move( open ), move( need ), r1->cost + r2->cost );
     
    12401397                        finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    12411398                        if ( finder3.candidates.empty() ) return;
     1399
     1400                        reason.code = NoMatch;
    12421401
    12431402                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    12561415                                                ast::AssertionSet have;
    12571416
    1258                                                 // unify true and false results, then infer parameters to produce new 
     1417                                                // unify true and false results, then infer parameters to produce new
    12591418                                                // candidates
    12601419                                                ast::ptr< ast::Type > common;
    1261                                                 if ( 
    1262                                                         unify( 
    1263                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 
    1264                                                                 common ) 
     1420                                                if (
     1421                                                        unify(
     1422                                                                r2->expr->result, r3->expr->result, env, need, have, open, symtab,
     1423                                                                common )
    12651424                                                ) {
    12661425                                                        // generate typed expression
    1267                                                         ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 
     1426                                                        ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
    12681427                                                                conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    12691428                                                        newExpr->result = common ? common : r2->expr->result;
    12701429                                                        // convert both options to result type
    12711430                                                        Cost cost = r1->cost + r2->cost + r3->cost;
    1272                                                         newExpr->arg2 = computeExpressionConversionCost( 
     1431                                                        newExpr->arg2 = computeExpressionConversionCost(
    12731432                                                                newExpr->arg2, newExpr->result, symtab, env, cost );
    12741433                                                        newExpr->arg3 = computeExpressionConversionCost(
     
    12871446                        ast::TypeEnvironment env{ tenv };
    12881447                        ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
    1289                        
     1448
    12901449                        CandidateFinder finder2{ symtab, env };
    12911450                        finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     
    13171476                        finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    13181477                        if ( finder2.candidates.empty() ) return;
     1478
     1479                        reason.code = NoMatch;
    13191480
    13201481                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    13301491
    13311492                                        ast::ptr< ast::Type > common;
    1332                                         if ( 
    1333                                                 unify( 
    1334                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab, 
    1335                                                         common ) 
     1493                                        if (
     1494                                                unify(
     1495                                                        r1->expr->result, r2->expr->result, env, need, have, open, symtab,
     1496                                                        common )
    13361497                                        ) {
    13371498                                                // generate new expression
    1338                                                 ast::RangeExpr * newExpr = 
     1499                                                ast::RangeExpr * newExpr =
    13391500                                                        new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    13401501                                                newExpr->result = common ? common : r1->expr->result;
    13411502                                                // add candidate
    13421503                                                CandidateRef newCand = std::make_shared<Candidate>(
    1343                                                         newExpr, move( env ), move( open ), move( need ), 
     1504                                                        newExpr, move( env ), move( open ), move( need ),
    13441505                                                        r1->cost + r2->cost );
    13451506                                                inferParameters( newCand, candidates );
     
    13501511
    13511512                void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1352                         std::vector< CandidateFinder > subCandidates = 
     1513                        std::vector< CandidateFinder > subCandidates =
    13531514                                selfFinder.findSubExprs( tupleExpr->exprs );
    13541515                        std::vector< CandidateList > possibilities;
     
    13701531
    13711532                                addCandidate(
    1372                                         new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 
     1533                                        new ast::TupleExpr{ tupleExpr->location, move( exprs ) },
    13731534                                        move( env ), move( open ), move( need ), sumCost( subs ) );
    13741535                        }
     
    14101571                                // calculate target type
    14111572                                const ast::Type * toType = resolveTypeof( initAlt.type, symtab );
    1412                                 toType = SymTab::validateType( initExpr->location, toType, symtab );
     1573                                // toType = SymTab::validateType( initExpr->location, toType, symtab );
    14131574                                toType = adjustExprType( toType, tenv, symtab );
    1414                                 // The call to find must occur inside this loop, otherwise polymorphic return 
    1415                                 // types are not bound to the initialization type, since return type variables are 
    1416                                 // only open for the duration of resolving the UntypedExpr. 
     1575                                // The call to find must occur inside this loop, otherwise polymorphic return
     1576                                // types are not bound to the initialization type, since return type variables are
     1577                                // only open for the duration of resolving the UntypedExpr.
    14171578                                CandidateFinder finder{ symtab, tenv, toType };
    14181579                                finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    14191580                                for ( CandidateRef & cand : finder.candidates ) {
     1581                                        if(reason.code == NotFound) reason.code = NoMatch;
     1582
    14201583                                        ast::TypeEnvironment env{ cand->env };
    14211584                                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     
    14261589                                        )
    14271590
    1428                                         // It is possible that a cast can throw away some values in a multiply-valued 
    1429                                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 
    1430                                         // the subexpression results that are cast directly. The candidate is invalid 
     1591                                        // It is possible that a cast can throw away some values in a multiply-valued
     1592                                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
     1593                                        // the subexpression results that are cast directly. The candidate is invalid
    14311594                                        // if it has fewer results than there are types to cast to.
    14321595                                        int discardedValues = cand->expr->result->size() - toType->size();
     
    14341597
    14351598                                        // unification run for side-effects
    1436                                         unify( toType, cand->expr->result, env, need, have, open, symtab );
    1437                                         Cost thisCost = castCost( cand->expr->result, toType, symtab, env );
    1438                                        
     1599                                        bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
     1600                                        (void) canUnify;
     1601                                        Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1602                                                symtab, env );
     1603                                        PRINT(
     1604                                                Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1605                                                        symtab, env );
     1606                                                std::cerr << "Considering initialization:";
     1607                                                std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
     1608                                                std::cerr << std::endl << "  TO: "   << toType             << std::endl;
     1609                                                std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
     1610                                                std::cerr << std::endl << "  Legacy cost " << legacyCost;
     1611                                                std::cerr << std::endl << "  New cost " << thisCost;
     1612                                                std::cerr << std::endl;
     1613                                        )
    14391614                                        if ( thisCost != Cost::infinity ) {
    14401615                                                // count one safe conversion for each value that is thrown away
    14411616                                                thisCost.incSafe( discardedValues );
    1442                                                 CandidateRef newCand = std::make_shared<Candidate>( 
    1443                                                         new ast::InitExpr{ 
    1444                                                                 initExpr->location, restructureCast( cand->expr, toType ), 
    1445                                                                 initAlt.designation }, 
    1446                                                         copy( cand->env ), move( open ), move( need ), cand->cost, thisCost );
     1617                                                CandidateRef newCand = std::make_shared<Candidate>(
     1618                                                        new ast::InitExpr{
     1619                                                                initExpr->location, restructureCast( cand->expr, toType ),
     1620                                                                initAlt.designation },
     1621                                                        move(env), move( open ), move( need ), cand->cost, thisCost );
    14471622                                                inferParameters( newCand, matches );
    14481623                                        }
    14491624                                }
     1625
    14501626                        }
    14511627
     
    14691645        };
    14701646
    1471         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1647        // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
     1648        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    14721649        /// return type. Skips ambiguous candidates.
    1473         CandidateList pruneCandidates( CandidateList & candidates ) {
    1474                 struct PruneStruct {
    1475                         CandidateRef candidate;
    1476                         bool ambiguous;
    1477 
    1478                         PruneStruct() = default;
    1479                         PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
    1480                 };
    1481 
    1482                 // find lowest-cost candidate for each type
    1483                 std::unordered_map< std::string, PruneStruct > selected;
    1484                 for ( CandidateRef & candidate : candidates ) {
    1485                         std::string mangleName;
     1650
     1651} // anonymous namespace
     1652
     1653bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
     1654        struct PruneStruct {
     1655                CandidateRef candidate;
     1656                bool ambiguous;
     1657
     1658                PruneStruct() = default;
     1659                PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
     1660        };
     1661
     1662        // find lowest-cost candidate for each type
     1663        std::unordered_map< std::string, PruneStruct > selected;
     1664        // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
     1665        std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
     1666        for ( CandidateRef & candidate : candidates ) {
     1667                std::string mangleName;
     1668                {
     1669                        ast::ptr< ast::Type > newType = candidate->expr->result;
     1670                        assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
     1671                        candidate->env.apply( newType );
     1672                        mangleName = Mangle::mangle( newType );
     1673                }
     1674
     1675                auto found = selected.find( mangleName );
     1676                if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
     1677                        PRINT(
     1678                                std::cerr << "cost " << candidate->cost << " loses to "
     1679                                        << found->second.candidate->cost << std::endl;
     1680                        )
     1681                        continue;
     1682                }
     1683
     1684                // xxx - when do satisfyAssertions produce more than 1 result?
     1685                // this should only happen when initial result type contains
     1686                // unbound type parameters, then it should never be pruned by
     1687                // the previous step, since renameTyVars guarantees the mangled name
     1688                // is unique.
     1689                CandidateList satisfied;
     1690                bool needRecomputeKey = false;
     1691                if (candidate->need.empty()) {
     1692                        satisfied.emplace_back(candidate);
     1693                }
     1694                else {
     1695                        satisfyAssertions(candidate, localSyms, satisfied, errors);
     1696                        needRecomputeKey = true;
     1697                }
     1698
     1699                for (auto & newCand : satisfied) {
     1700                        // recomputes type key, if satisfyAssertions changed it
     1701                        if (needRecomputeKey)
    14861702                        {
    1487                                 ast::ptr< ast::Type > newType = candidate->expr->result;
    1488                                 candidate->env.apply( newType );
     1703                                ast::ptr< ast::Type > newType = newCand->expr->result;
     1704                                assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
     1705                                newCand->env.apply( newType );
    14891706                                mangleName = Mangle::mangle( newType );
    14901707                        }
    1491 
    14921708                        auto found = selected.find( mangleName );
    14931709                        if ( found != selected.end() ) {
    1494                                 if ( candidate->cost < found->second.candidate->cost ) {
     1710                                if ( newCand->cost < found->second.candidate->cost ) {
    14951711                                        PRINT(
    1496                                                 std::cerr << "cost " << candidate->cost << " beats "
     1712                                                std::cerr << "cost " << newCand->cost << " beats "
    14971713                                                        << found->second.candidate->cost << std::endl;
    14981714                                        )
    14991715
    1500                                         found->second = PruneStruct{ candidate };
    1501                                 } else if ( candidate->cost == found->second.candidate->cost ) {
    1502                                         // if one of the candidates contains a deleted identifier, can pick the other, 
    1503                                         // since deleted expressions should not be ambiguous if there is another option 
     1716                                        found->second = PruneStruct{ newCand };
     1717                                } else if ( newCand->cost == found->second.candidate->cost ) {
     1718                                        // if one of the candidates contains a deleted identifier, can pick the other,
     1719                                        // since deleted expressions should not be ambiguous if there is another option
    15041720                                        // that is at least as good
    1505                                         if ( findDeletedExpr( candidate->expr ) ) {
     1721                                        if ( findDeletedExpr( newCand->expr ) ) {
    15061722                                                // do nothing
    15071723                                                PRINT( std::cerr << "candidate is deleted" << std::endl; )
    15081724                                        } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
    15091725                                                PRINT( std::cerr << "current is deleted" << std::endl; )
    1510                                                 found->second = PruneStruct{ candidate };
     1726                                                found->second = PruneStruct{ newCand };
    15111727                                        } else {
    15121728                                                PRINT( std::cerr << "marking ambiguous" << std::endl; )
    15131729                                                found->second.ambiguous = true;
    15141730                                        }
    1515                                 } else {
     1731                                } else {
     1732                                        // xxx - can satisfyAssertions increase the cost?
    15161733                                        PRINT(
    1517                                                 std::cerr << "cost " << candidate->cost << " loses to "
     1734                                                std::cerr << "cost " << newCand->cost << " loses to "
    15181735                                                        << found->second.candidate->cost << std::endl;
    1519                                         )
     1736                                        )       
    15201737                                }
    15211738                        } else {
    1522                                 selected.emplace_hint( found, mangleName, candidate );
    1523                         }
    1524                 }
    1525 
    1526                 // report unambiguous min-cost candidates
    1527                 CandidateList out;
    1528                 for ( auto & target : selected ) {
    1529                         if ( target.second.ambiguous ) continue;
    1530 
    1531                         CandidateRef cand = target.second.candidate;
    1532                        
    1533                         ast::ptr< ast::Type > newResult = cand->expr->result;
    1534                         cand->env.applyFree( newResult );
    1535                         cand->expr = ast::mutate_field(
    1536                                 cand->expr.get(), &ast::Expr::result, move( newResult ) );
    1537                        
    1538                         out.emplace_back( cand );
    1539                 }
    1540                 return out;
     1739                                selected.emplace_hint( found, mangleName, newCand );
     1740                        }
     1741                }
    15411742        }
    15421743
    1543 } // anonymous namespace
     1744        // report unambiguous min-cost candidates
     1745        // CandidateList out;
     1746        for ( auto & target : selected ) {
     1747                if ( target.second.ambiguous ) continue;
     1748
     1749                CandidateRef cand = target.second.candidate;
     1750
     1751                ast::ptr< ast::Type > newResult = cand->expr->result;
     1752                cand->env.applyFree( newResult );
     1753                cand->expr = ast::mutate_field(
     1754                        cand->expr.get(), &ast::Expr::result, move( newResult ) );
     1755
     1756                out.emplace_back( cand );
     1757        }
     1758        // if everything is lost in satisfyAssertions, report the error
     1759        return !selected.empty();
     1760}
    15441761
    15451762void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
     
    15491766
    15501767        if ( mode.failFast && candidates.empty() ) {
    1551                 SemanticError( expr, "No reasonable alternatives for expression " );
     1768                switch(finder.core.reason.code) {
     1769                case Finder::NotFound:
     1770                        { SemanticError( expr, "No alternatives for expression " ); break; }
     1771                case Finder::NoMatch:
     1772                        { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
     1773                case Finder::ArgsToFew:
     1774                case Finder::ArgsToMany:
     1775                case Finder::RetsToFew:
     1776                case Finder::RetsToMany:
     1777                case Finder::NoReason:
     1778                default:
     1779                        { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
     1780                }
    15521781        }
    15531782
     1783        /*
    15541784        if ( mode.satisfyAssns || mode.prune ) {
    15551785                // trim candidates to just those where the assertions are satisfiable
     
    15581788                std::vector< std::string > errors;
    15591789                for ( CandidateRef & candidate : candidates ) {
    1560                         satisfyAssertions( candidate, symtab, satisfied, errors );
     1790                        satisfyAssertions( candidate, localSyms, satisfied, errors );
    15611791                }
    15621792
     
    15741804                candidates = move( satisfied );
    15751805        }
     1806        */
    15761807
    15771808        if ( mode.prune ) {
     
    15821813                )
    15831814
    1584                 CandidateList pruned = pruneCandidates( candidates );
    1585                
     1815                CandidateList pruned;
     1816                std::vector<std::string> errors;
     1817                bool found = pruneCandidates( candidates, pruned, errors );
     1818
    15861819                if ( mode.failFast && pruned.empty() ) {
    15871820                        std::ostringstream stream;
    1588                         CandidateList winners = findMinCost( candidates );
    1589                         stream << "Cannot choose between " << winners.size() << " alternatives for "
    1590                                 "expression\n";
    1591                         ast::print( stream, expr );
    1592                         stream << " Alternatives are:\n";
    1593                         print( stream, winners, 1 );
    1594                         SemanticError( expr->location, stream.str() );
     1821                        if (found) {           
     1822                                CandidateList winners = findMinCost( candidates );
     1823                                stream << "Cannot choose between " << winners.size() << " alternatives for "
     1824                                        "expression\n";
     1825                                ast::print( stream, expr );
     1826                                stream << " Alternatives are:\n";
     1827                                print( stream, winners, 1 );
     1828                                SemanticError( expr->location, stream.str() );
     1829                        }
     1830                        else {
     1831                                stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1832                                for ( const auto& err : errors ) {
     1833                                        stream << err;
     1834                                }
     1835                                SemanticError( expr->location, stream.str() );
     1836                        }
    15951837                }
    15961838
     
    16021844                )
    16031845                PRINT(
    1604                         std::cerr << "there are " << candidates.size() << " alternatives after elimination" 
     1846                        std::cerr << "there are " << candidates.size() << " alternatives after elimination"
    16051847                                << std::endl;
    16061848                )
    16071849        }
    16081850
    1609         // adjust types after pruning so that types substituted by pruneAlternatives are correctly 
     1851        // adjust types after pruning so that types substituted by pruneAlternatives are correctly
    16101852        // adjusted
    16111853        if ( mode.adjust ) {
    16121854                for ( CandidateRef & r : candidates ) {
    1613                         r->expr = ast::mutate_field( 
    1614                                 r->expr.get(), &ast::Expr::result, 
    1615                                 adjustExprType( r->expr->result, r->env, symtab ) );
     1855                        r->expr = ast::mutate_field(
     1856                                r->expr.get(), &ast::Expr::result,
     1857                                adjustExprType( r->expr->result, r->env, localSyms ) );
    16161858                }
    16171859        }
     
    16251867}
    16261868
    1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 
    1628         const std::vector< ast::ptr< ast::Expr > > & xs 
     1869std::vector< CandidateFinder > CandidateFinder::findSubExprs(
     1870        const std::vector< ast::ptr< ast::Expr > > & xs
    16291871) {
    16301872        std::vector< CandidateFinder > out;
    16311873
    16321874        for ( const auto & x : xs ) {
    1633                 out.emplace_back( symtab, env );
     1875                out.emplace_back( localSyms, env );
    16341876                out.back().find( x, ResolvMode::withAdjustment() );
    1635                
     1877
    16361878                PRINT(
    16371879                        std::cerr << "findSubExprs" << std::endl;
  • src/ResolvExpr/CandidateFinder.hpp

    r3c64c668 r58fe85a  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Wed Jun 5 14:30:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct  1  9:51:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    2828struct CandidateFinder {
    2929        CandidateList candidates;          ///< List of candidate resolutions
    30         const ast::SymbolTable & symtab;   ///< Symbol table to lookup candidates
     30        const ast::SymbolTable & localSyms;   ///< Symbol table to lookup candidates
    3131        const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
    3232        ast::ptr< ast::Type > targetType;  ///< Target type for resolution
     33        std::set< std::string > otypeKeys;  /// different type may map to same key
    3334
    34         CandidateFinder( 
    35                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     35        CandidateFinder(
     36                const ast::SymbolTable & syms, const ast::TypeEnvironment & env,
    3637                const ast::Type * tt = nullptr )
    37         : candidates(), symtab( symtab ), env( env ), targetType( tt ) {}
     38        : candidates(), localSyms( syms ), env( env ), targetType( tt ) {}
    3839
    3940        /// Fill candidates with feasible resolutions for `expr`
    4041        void find( const ast::Expr * expr, ResolvMode mode = {} );
     42        bool pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors );
    4143
    4244        /// Runs new candidate finder on each element in xs, returning the list of finders
     
    4951        iterator begin() { return candidates.begin(); }
    5052        const_iterator begin() const { return candidates.begin(); }
    51        
     53
    5254        iterator end() { return candidates.end(); }
    5355        const_iterator end() const { return candidates.end(); }
     
    5557
    5658/// Computes conversion cost between two types
    57 Cost computeConversionCost( 
    58         const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
    59         const ast::TypeEnvironment & env );
     59Cost computeConversionCost(
     60        const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
     61        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    6062
    6163} // namespace ResolvExpr
  • src/ResolvExpr/CastCost.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Sun May 17 06:57:43 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Aug  8 16:12:00 2019
    13 // Update Count     : 8
     12// Last Modified On : Tue Oct  4 15:00:00 2019
     13// Update Count     : 9
    1414//
    1515
     
    142142
    143143                CastCost_new(
    144                         const ast::Type * dst, const ast::SymbolTable & symtab,
     144                        const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
    145145                        const ast::TypeEnvironment & env, CostCalculation costFunc )
    146                 : ConversionCost_new( dst, symtab, env, costFunc ) {}
     146                : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {}
    147147
    148148                void postvisit( const ast::BasicType * basicType ) {
     
    152152                                cost = Cost::unsafe;
    153153                        } else {
    154                                 cost = conversionCost( basicType, dst, symtab, env );
     154                                cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
    155155                        }
    156156                }
     
    165165                                } else {
    166166                                        ast::TypeEnvironment newEnv{ env };
    167                                         if ( auto wParams = pointerType->base.as< ast::ParameterizedType >() ) {
     167                                        if ( auto wParams = pointerType->base.as< ast::FunctionType >() ) {
    168168                                                newEnv.add( wParams->forall );
    169169                                        }
     
    183183                }
    184184        };
     185
     186        #warning For overload resolution between the two versions.
     187        int localPtrsCastable(const ast::Type * t1, const ast::Type * t2,
     188                        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) {
     189                return ptrsCastable( t1, t2, symtab, env );
     190        }
     191        Cost localCastCost(
     192                const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     193                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     194        ) { return castCost( src, dst, srcIsLvalue, symtab, env ); }
    185195} // anonymous namespace
    186196
     197
     198
    187199Cost castCost(
    188         const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    189         const ast::TypeEnvironment & env
     200        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     201        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    190202) {
    191203        if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    192                 if ( const ast::EqvClass * eqvClass = env.lookup( typeInst->name ) ) {
     204                if ( const ast::EqvClass * eqvClass = env.lookup( *typeInst ) ) {
    193205                        // check cast cost against bound type, if present
    194206                        if ( eqvClass->bound ) {
    195                                 return castCost( src, eqvClass->bound, symtab, env );
     207                                return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
    196208                        } else {
    197209                                return Cost::infinity;
     
    201213                        auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
    202214                        if ( type->base ) {
    203                                 return castCost( src, type->base, symtab, env ) + Cost::safe;
     215                                return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
    204216                        }
    205217                }
     
    224236                #warning cast on ptrsCastable artifact of having two functions, remove when port done
    225237                return convertToReferenceCost(
    226                         src, refType, symtab, env,
    227                         ( int (*)(
    228                                 const ast::Type *, const ast::Type *, const ast::SymbolTable &,
    229                                 const ast::TypeEnvironment & )
    230                         ) ptrsCastable );
     238                        src, refType, srcIsLvalue, symtab, env, localPtrsCastable );
    231239        } else {
    232240                #warning cast on castCost artifact of having two functions, remove when port done
    233                 ast::Pass< CastCost_new > converter{
    234                         dst, symtab, env,
    235                         ( Cost (*)(
    236                                 const ast::Type *, const ast::Type *, const ast::SymbolTable &,
    237                                 const ast::TypeEnvironment & )
    238                         ) castCost };
     241                ast::Pass< CastCost_new > converter(
     242                        dst, srcIsLvalue, symtab, env, localCastCost );
    239243                src->accept( converter );
    240                 return converter.pass.cost;
     244                return converter.core.cost;
    241245        }
    242246}
  • src/ResolvExpr/CommonType.cc

    r3c64c668 r58fe85a  
    666666                const ast::OpenVarSet & open;
    667667        public:
     668                static size_t traceId;
    668669                ast::ptr< ast::Type > result;
    669670
     
    712713                        const ast::Type * base = oPtr->base;
    713714                        if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) {
    714                                 auto entry = open.find( var->name );
     715                                auto entry = open.find( *var );
    715716                                if ( entry != open.end() ) {
    716717                                        ast::AssertionSet need, have;
     
    893894        };
    894895
     896        // size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");
    895897        namespace {
    896898                ast::ptr< ast::Type > handleReference(
     
    939941                        ast::ptr< ast::Type > result;
    940942                        const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
    941                         const ast::ReferenceType * ref2 = type1.as< ast::ReferenceType >();
     943                        const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >();
    942944
    943945                        if ( depth1 > depth2 ) {
     
    966968                ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open };
    967969                type1->accept( visitor );
    968                 ast::ptr< ast::Type > result = visitor.pass.result;
     970                ast::ptr< ast::Type > result = visitor.core.result;
    969971
    970972                // handling for opaque type declarations (?)
  • src/ResolvExpr/ConversionCost.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Sun May 17 07:06:19 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Aug 12 10:21:00 2019
    13 // Update Count     : 27
     12// Last Modified On : Wed Jul 29 16:11:00 2020
     13// Update Count     : 28
    1414//
    1515
     
    392392        void ConversionCost::postvisit( const FunctionType * ) {}
    393393
    394         void ConversionCost::postvisit( const StructInstType * inst ) {
    395                 if ( const StructInstType * destAsInst = dynamic_cast< const StructInstType * >( dest ) ) {
    396                         if ( inst->name == destAsInst->name ) {
    397                                 cost = Cost::zero;
    398                         } // if
    399                 } // if
    400         }
    401 
    402         void ConversionCost::postvisit( const UnionInstType * inst ) {
    403                 if ( const UnionInstType * destAsInst = dynamic_cast< const UnionInstType * >( dest ) ) {
    404                         if ( inst->name == destAsInst->name ) {
    405                                 cost = Cost::zero;
    406                         } // if
    407                 } // if
    408         }
    409 
    410394        void ConversionCost::postvisit( const EnumInstType * ) {
    411395                static Type::Qualifiers q;
     
    497481        }
    498482
    499 static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
    500                 const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
    501         return ptrsAssignable( t1, t2, env );
    502 }
    503 
    504 // TODO: This is used for overload resolution. It might be able to be dropped once the old system
    505 // is removed.
    506 static Cost localConversionCost(
    507         const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    508         const ast::TypeEnvironment & env
    509 ) { return conversionCost( src, dst, symtab, env ); }
     483namespace {
     484        # warning For overload resolution between the two versions.
     485        int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
     486                        const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
     487                return ptrsAssignable( t1, t2, env );
     488        }
     489        Cost localConversionCost(
     490                const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     491                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     492        ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); }
     493}
    510494
    511495Cost conversionCost(
    512         const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    513         const ast::TypeEnvironment & env
     496        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     497        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    514498) {
    515499        if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    516                 if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
     500                if ( const ast::EqvClass * eqv = env.lookup( *inst ) ) {
    517501                        if ( eqv->bound ) {
    518                                 return conversionCost(src, eqv->bound, symtab, env );
     502                                return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
    519503                        } else {
    520504                                return Cost::infinity;
     
    524508                        assertf( type, "Unexpected typedef." );
    525509                        if ( type->base ) {
    526                                 return conversionCost( src, type->base, symtab, env ) + Cost::safe;
     510                                return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
    527511                        }
    528512                }
     
    534518        } else if ( const ast::ReferenceType * refType =
    535519                         dynamic_cast< const ast::ReferenceType * >( dst ) ) {
    536                 return convertToReferenceCost( src, refType, symtab, env, localPtrsAssignable );
     520                return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable );
    537521        } else {
    538                 ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
    539                 src->accept( converter );
    540                 return converter.pass.cost;
    541         }
    542 }
    543 
    544 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst,
     522                return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost );
     523        }
     524}
     525
     526static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    545527                int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    546                 NumCostCalculation func ) {
     528                PtrsCalculation func ) {
    547529        if ( 0 < diff ) {
    548530                Cost cost = convertToReferenceCost(
    549                         strict_dynamic_cast< const ast::ReferenceType * >( src )->base,
    550                         dst, (diff - 1), symtab, env, func );
     531                        strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst,
     532                        srcIsLvalue, (diff - 1), symtab, env, func );
    551533                cost.incReference();
    552534                return cost;
     
    554536                Cost cost = convertToReferenceCost(
    555537                        src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
    556                         (diff + 1), symtab, env, func );
     538                        srcIsLvalue, (diff + 1), symtab, env, func );
    557539                cost.incReference();
    558540                return cost;
     
    579561                        }
    580562                } else {
    581                         ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
    582                         src->accept( converter );
    583                         return converter.pass.cost;
     563                        return ast::Pass<ConversionCost_new>::read( src, dst, srcIsLvalue, symtab, env, localConversionCost );
    584564                }
    585565        } else {
     
    588568                assert( dstAsRef );
    589569                if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) {
    590                         if ( src->is_lvalue() ) {
     570                        if ( srcIsLvalue ) {
    591571                                if ( src->qualifiers == dstAsRef->base->qualifiers ) {
    592572                                        return Cost::reference;
     
    607587
    608588Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
    609             const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    610                 NumCostCalculation func ) {
     589                bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     590                PtrsCalculation func ) {
    611591        int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
    612         return convertToReferenceCost( src, dst, sdepth - ddepth, symtab, env, func );
     592        return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func );
    613593}
    614594
     
    667647        assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
    668648
    669         cost = costCalc( refType->base, dst, symtab, env );
     649        cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
    670650        if ( refType->base->qualifiers == dst->qualifiers ) {
    671651                cost.incReference();
     
    681661}
    682662
    683 void ConversionCost_new::postvisit( const ast::StructInstType * structInstType ) {
    684         if ( const ast::StructInstType * dstAsInst =
    685                         dynamic_cast< const ast::StructInstType * >( dst ) ) {
    686                 if ( structInstType->name == dstAsInst->name ) {
    687                         cost = Cost::zero;
    688                 }
    689         }
    690 }
    691 
    692 void ConversionCost_new::postvisit( const ast::UnionInstType * unionInstType ) {
    693         if ( const ast::UnionInstType * dstAsInst =
    694                         dynamic_cast< const ast::UnionInstType * >( dst ) ) {
    695                 if ( unionInstType->name == dstAsInst->name ) {
    696                         cost = Cost::zero;
    697                 }
    698         }
    699 }
    700 
    701663void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
    702664        (void)enumInstType;
    703         static const ast::BasicType integer( ast::BasicType::SignedInt );
    704         cost = costCalc( &integer, dst, symtab, env );
     665        static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
     666        cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
    705667        if ( cost < Cost::unsafe ) {
    706668                cost.incSafe();
     
    713675
    714676void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
    715         if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
    716                 cost = costCalc( eqv->bound, dst, symtab, env );
     677        if ( const ast::EqvClass * eqv = env.lookup( *typeInstType ) ) {
     678                cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
    717679        } else if ( const ast::TypeInstType * dstAsInst =
    718680                        dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    719                 if ( typeInstType->name == dstAsInst->name ) {
     681                if ( *typeInstType == *dstAsInst ) {
    720682                        cost = Cost::zero;
    721683                }
     
    724686                assertf( type, "Unexpected typedef.");
    725687                if ( type->base ) {
    726                         cost = costCalc( type->base, dst, symtab, env ) + Cost::safe;
     688                        cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe;
    727689                }
    728690        }
     
    737699                auto dstEnd = dstAsTuple->types.end();
    738700                while ( srcIt != srcEnd && dstIt != dstEnd ) {
    739                         Cost newCost = costCalc( * srcIt++, * dstIt++, symtab, env );
     701                        Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env );
    740702                        if ( newCost == Cost::infinity ) {
    741703                                return;
     
    772734                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    773735                }
     736        } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
     737                cost = Cost::zero;
     738                // +1 for zero_t ->, +1 for disambiguation
     739                cost.incSafe( maxIntCost + 2 );
    774740        }
    775741}
     
    789755                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    790756                }
    791         } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
    792                 cost = Cost::zero;
    793                 cost.incSafe( maxIntCost + 2 );
    794         }
    795 }
    796 
     757        }
     758}
     759// size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
    797760
    798761} // namespace ResolvExpr
  • src/ResolvExpr/ConversionCost.h

    r3c64c668 r58fe85a  
    1010// Created On       : Sun May 17 09:37:28 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Aug  8 16:13:00 2019
    13 // Update Count     : 6
     12// Last Modified On : Wed Jul 29 16:12:00 2020
     13// Update Count     : 7
    1414//
    1515
     
    5151                void postvisit( const ReferenceType * refType );
    5252                void postvisit( const FunctionType * functionType );
    53                 void postvisit( const StructInstType * aggregateUseType );
    54                 void postvisit( const UnionInstType * aggregateUseType );
    5553                void postvisit( const EnumInstType * aggregateUseType );
    5654                void postvisit( const TraitInstType * aggregateUseType );
     
    7472
    7573// Some function pointer types, differ in return type.
    76 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *,
     74using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool,
    7775        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    78 using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,
     76using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *,
    7977        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    8078
     
    8381protected:
    8482        const ast::Type * dst;
     83        bool srcIsLvalue;
    8584        const ast::SymbolTable & symtab;
    8685        const ast::TypeEnvironment & env;
    8786        CostCalculation costCalc;
    8887public:
     88        static size_t traceId;
    8989        Cost cost;
     90        Cost result() { return cost; }
    9091
    91         ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,
     92        ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
    9293                        const ast::TypeEnvironment & env, CostCalculation costCalc ) :
    93                 dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity )
     94                dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ),
     95                costCalc( costCalc ), cost( Cost::infinity )
    9496        {}
    9597
     
    102104        void postvisit( const ast::ReferenceType * refType );
    103105        void postvisit( const ast::FunctionType * functionType );
    104         void postvisit( const ast::StructInstType * structInstType );
    105         void postvisit( const ast::UnionInstType * unionInstType );
    106106        void postvisit( const ast::EnumInstType * enumInstType );
    107107        void postvisit( const ast::TraitInstType * traitInstType );
     
    114114
    115115Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
    116         const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func );
     116        bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
     117        PtrsCalculation func );
    117118
    118119} // namespace ResolvExpr
  • src/ResolvExpr/CurrentObject.cc

    r3c64c668 r58fe85a  
    2121#include <string>                      // for string, operator<<, allocator
    2222
     23#include "AST/Copy.hpp"                // for shallowCopy
    2324#include "AST/Expr.hpp"                // for InitAlternative
    2425#include "AST/GenericSubstitution.hpp" // for genericSubstitution
    2526#include "AST/Init.hpp"                // for Designation
    2627#include "AST/Node.hpp"                // for readonly
     28#include "AST/Print.hpp"                // for readonly
    2729#include "AST/Type.hpp"
    2830#include "Common/Indenter.h"           // for Indenter, operator<<
     
    592594        class SimpleIterator final : public MemberIterator {
    593595                CodeLocation location;
    594                 readonly< Type > type = nullptr;
     596                const Type * type = nullptr;
    595597        public:
    596598                SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
    597599
    598                 void setPosition( 
    599                         std::deque< ptr< Expr > >::const_iterator begin, 
     600                void setPosition(
     601                        std::deque< ptr< Expr > >::const_iterator begin,
    600602                        std::deque< ptr< Expr > >::const_iterator end
    601603                ) override {
     
    628630        class ArrayIterator final : public MemberIterator {
    629631                CodeLocation location;
    630                 readonly< ArrayType > array = nullptr;
    631                 readonly< Type > base = nullptr;
     632                const ArrayType * array = nullptr;
     633                const Type * base = nullptr;
    632634                size_t index = 0;
    633635                size_t size = 0;
     
    637639                        auto res = eval(expr);
    638640                        if ( ! res.second ) {
    639                                 SemanticError( location, 
     641                                SemanticError( location,
    640642                                        toString("Array designator must be a constant expression: ", expr ) );
    641643                        }
     
    644646
    645647        public:
    646                 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 
     648                ArrayIterator( const CodeLocation & loc, const ArrayType * at )
    647649                : location( loc ), array( at ), base( at->base ) {
    648650                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     
    655657
    656658                void setPosition( const Expr * expr ) {
    657                         // need to permit integer-constant-expressions, including: integer constants, 
    658                         // enumeration constants, character constants, sizeof expressions, alignof expressions, 
     659                        // need to permit integer-constant-expressions, including: integer constants,
     660                        // enumeration constants, character constants, sizeof expressions, alignof expressions,
    659661                        // cast expressions
    660662                        if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    662664                                        index = constExpr->intValue();
    663665                                } catch ( SemanticErrorException & ) {
    664                                         SemanticError( expr, 
     666                                        SemanticError( expr,
    665667                                                "Constant expression of non-integral type in array designator: " );
    666668                                }
    667669                        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
    668670                                setPosition( castExpr->arg );
    669                         } else if ( 
    670                                 dynamic_cast< const SizeofExpr * >( expr ) 
    671                                 || dynamic_cast< const AlignofExpr * >( expr ) 
     671                        } else if (
     672                                dynamic_cast< const SizeofExpr * >( expr )
     673                                || dynamic_cast< const AlignofExpr * >( expr )
    672674                        ) {
    673675                                index = 0;
    674676                        } else {
    675                                 assertf( false, 
     677                                assertf( false,
    676678                                        "bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
    677679                        }
    678680                }
    679681
    680                 void setPosition( 
    681                         std::deque< ptr< Expr > >::const_iterator begin, 
     682                void setPosition(
     683                        std::deque< ptr< Expr > >::const_iterator begin,
    682684                        std::deque< ptr< Expr > >::const_iterator end
    683685                ) override {
     
    758760                }
    759761
    760                 AggregateIterator( 
    761                         const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 
     762                AggregateIterator(
     763                        const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
    762764                        const MemberList & ms )
    763                 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 
     765                : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
    764766                  sub( genericSubstitution( i ) ) {
    765767                        PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
     
    768770
    769771        public:
    770                 void setPosition( 
    771                         std::deque< ptr< Expr > >::const_iterator begin, 
     772                void setPosition(
     773                        std::deque< ptr< Expr > >::const_iterator begin,
    772774                        std::deque< ptr< Expr > >::const_iterator end
    773775                ) final {
     
    786788                                        return;
    787789                                }
    788                                 assertf( false, 
     790                                assertf( false,
    789791                                        "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    790792                        } else {
    791                                 assertf( false, 
     793                                assertf( false,
    792794                                        "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
    793795                        }
     
    803805                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    804806                                        // need to substitute for generic types so that casts are to concrete types
     807                                        alt.type = shallowCopy(alt.type.get());
    805808                                        PRINT( std::cerr << "  type is: " << alt.type; )
    806809                                        sub.apply( alt.type ); // also apply to designation??
     
    842845                                for ( InitAlternative & alt : ret ) {
    843846                                        PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    844                                         alt.designation.get_and_mutate()->designators.emplace_front( 
     847                                        alt.designation.get_and_mutate()->designators.emplace_front(
    845848                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    846849                                }
     
    897900        class TupleIterator final : public AggregateIterator {
    898901        public:
    899                 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 
    900                 : AggregateIterator( 
    901                         loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 
     902                TupleIterator( const CodeLocation & loc, const TupleType * inst )
     903                : AggregateIterator(
     904                        loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
    902905                ) {}
    903906
     
    920923
    921924        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) {
    922                 if ( auto aggr = dynamic_cast< const ReferenceToType * >( type ) ) {
     925                if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
    923926                        if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
    924927                                return new StructIterator{ loc, sit };
     
    926929                                return new UnionIterator{ loc, uit };
    927930                        } else {
    928                                 assertf( 
    929                                         dynamic_cast< const EnumInstType * >( aggr )
    930                                                 || dynamic_cast< const TypeInstType * >( aggr ),
    931                                         "Encountered unhandled ReferenceToType in createMemberIterator: %s",
     931                                assertf(
     932                                        dynamic_cast< const EnumInstType * >( type )
     933                                                || dynamic_cast< const TypeInstType * >( type ),
     934                                        "Encountered unhandled BaseInstType in createMemberIterator: %s",
    932935                                                toString( type ).c_str() );
    933936                                return new SimpleIterator{ loc, type };
     
    949952                using DesignatorChain = std::deque< ptr< Expr > >;
    950953                PRINT( std::cerr << "___findNext" << std::endl; )
    951                
     954
    952955                // find all the d's
    953956                std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
     
    962965                                        DesignatorChain & d = *dit;
    963966                                        PRINT( std::cerr << "____actual: " << t << std::endl; )
    964                                         if ( auto refType = dynamic_cast< const ReferenceToType * >( t ) ) {
     967                                        if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) {
    965968                                                // concatenate identical field names
    966969                                                for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
     
    10131016                // set new designators
    10141017                assertf( ! objStack.empty(), "empty object stack when setting designation" );
    1015                 Designation * actualDesignation = 
     1018                Designation * actualDesignation =
    10161019                        new Designation{ designation->location, DesignatorChain{d} };
    10171020                objStack.back()->setPosition( d ); // destroys d
  • src/ResolvExpr/FindOpenVars.cc

    r3c64c668 r58fe85a  
    112112                                // mark open/closed variables
    113113                                if ( nextIsOpen ) {
    114                                         for ( const ast::TypeDecl * decl : type->forall ) {
    115                                                 open[ decl->name ] = ast::TypeDecl::Data{ decl };
    116                                                 for ( const ast::DeclWithType * assert : decl->assertions ) {
    117                                                         need[ assert ].isUsed = false;
    118                                                 }
     114                                        for ( auto & decl : type->forall ) {
     115                                                open[ *decl ] = ast::TypeDecl::Data{ decl->base };
     116                                        }
     117                                        for ( auto & assert : type->assertions ) {
     118                                                need[ assert ].isUsed = false;
    119119                                        }
    120120                                } else {
    121                                         for ( const ast::TypeDecl * decl : type->forall ) {
    122                                                 closed[ decl->name ] = ast::TypeDecl::Data{ decl };
    123                                                 for ( const ast::DeclWithType * assert : decl->assertions ) {
    124                                                         have[ assert ].isUsed = false;
    125                                                 }
     121                                        for ( auto & decl : type->forall ) {
     122                                                closed[ *decl ] = ast::TypeDecl::Data{ decl->base };   
     123                                        }
     124                                        for ( auto & assert : type->assertions ) {
     125                                                have[ assert ].isUsed = false;
    126126                                        }
    127127                                }
  • src/ResolvExpr/PolyCost.cc

    r3c64c668 r58fe85a  
    5858
    5959// TODO: When the old PolyCost is torn out get rid of the _new suffix.
    60 struct PolyCost_new {
     60class PolyCost_new {
     61        const ast::SymbolTable &symtab;
     62public:
    6163        int result;
    62         const ast::SymbolTable &symtab;
    6364        const ast::TypeEnvironment &env_;
    6465
    65         PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :
    66                 result( 0 ), symtab( symtab ), env_( env ) {}
     66        PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
     67        : symtab( symtab ), result( 0 ), env_( env ) {}
    6768
    6869        void previsit( const ast::TypeInstType * type ) {
    69                 if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {
     70                if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) {
    7071                        if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
    7172                                if ( symtab.lookupType( otherType->name ) ) {
     
    8687        ast::Pass<PolyCost_new> costing( symtab, env );
    8788        type->accept( costing );
    88         return costing.pass.result;
     89        return costing.core.result;
    8990}
    9091
  • src/ResolvExpr/PtrsAssignable.cc

    r3c64c668 r58fe85a  
    134134        }
    135135        void postvisit( const ast::TypeInstType * inst ) {
    136                 if ( const ast::EqvClass * eqv = typeEnv.lookup( inst->name ) ) {
     136                if ( const ast::EqvClass * eqv = typeEnv.lookup( *inst ) ) {
    137137                        if ( eqv->bound ) {
    138138                                // T * = S * for any S depends on the type bound to T
     
    146146                const ast::TypeEnvironment & env ) {
    147147        if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    148                 if ( const ast::EqvClass * eqv = env.lookup( dstAsInst->name ) ) {
     148                if ( const ast::EqvClass * eqv = env.lookup( *dstAsInst ) ) {
    149149                        return ptrsAssignable( src, eqv->bound, env );
    150150                }
     
    155155                ast::Pass<PtrsAssignable_new> visitor( dst, env );
    156156                src->accept( visitor );
    157                 return visitor.pass.result;
     157                return visitor.core.result;
    158158        }
    159159
  • src/ResolvExpr/PtrsCastable.cc

    r3c64c668 r58fe85a  
    180180                                        }
    181181                                }
    182                         } else if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
     182                        } else if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
    183183                                if ( eqvClass->data.kind == ast::TypeDecl::Ftype ) {
    184184                                        return -1;
     
    283283) {
    284284        if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    285                 if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
     285                if ( const ast::EqvClass * eqvClass = env.lookup( *inst ) ) {
    286286                        return ptrsAssignable( src, eqvClass->bound, env );
    287287                }
     
    293293                ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab };
    294294                src->accept( ptrs );
    295                 return ptrs.pass.result;
     295                return ptrs.core.result;
    296296        }
    297297}
  • src/ResolvExpr/RenameVars.cc

    r3c64c668 r58fe85a  
    3030#include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
    3131
     32#include "AST/Copy.hpp"
     33
    3234namespace ResolvExpr {
    3335
     
    3638                int level = 0;
    3739                int resetCount = 0;
     40
     41                int next_expr_id = 1;
     42                int next_usage_id = 1;
    3843                ScopedMap< std::string, std::string > nameMap;
    39 
     44                ScopedMap< std::string, ast::TypeInstType::TypeEnvKey > idMap;
    4045        public:
    4146                void reset() {
     
    4449                }
    4550
    46                 using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;
    47 
    4851                void rename( TypeInstType * type ) {
    49                         mapConstIterator it = nameMap.find( type->name );
     52                        auto it = nameMap.find( type->name );
    5053                        if ( it != nameMap.end() ) {
    5154                                type->name = it->second;
    5255                        }
     56                }
     57
     58                void nextUsage() {
     59                        ++next_usage_id;
    5360                }
    5461
     
    6572                                        // ditto for assertion names, the next level in
    6673                                        level++;
    67                                         // acceptAll( td->assertions, *this );
    68                                 } // for
    69                         } // if
     74                                }
     75                        }
    7076                }
    7177
     
    7783
    7884                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
    79                         mapConstIterator it = nameMap.find( type->name );
    80                         if ( it != nameMap.end() ) {
    81                                 ast::TypeInstType * mutType = ast::mutate( type );
    82                                 mutType->name = it->second;
    83                     type = mutType;
    84                         }
     85                        // rename
     86                        auto it = idMap.find( type->name );
     87                        if ( it != idMap.end() ) {
     88                                // unconditionally mutate because map will *always* have different name
     89                                ast::TypeInstType * mut = ast::shallowCopy( type );
     90                                // reconcile base node since some copies might have been made
     91                                mut->base = it->second.base;
     92                                mut->formal_usage = it->second.formal_usage;
     93                                mut->expr_id = it->second.expr_id;
     94                    type = mut;
     95                        }
     96
    8597                        return type;
    8698                }
    8799
    88                 template<typename NodeT>
    89                 const NodeT * openLevel( const NodeT * type ) {
    90                         if ( !type->forall.empty() ) {
    91                                 nameMap.beginScope();
    92                                 // Load new names from this forall clause and perform renaming.
    93                                 NodeT * mutType = ast::mutate( type );
    94                                 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
    95                                         std::ostringstream output;
    96                                         output << "_" << resetCount << "_" << level << "_" << td->name;
    97                                         std::string newname( output.str() );
    98                                         nameMap[ td->name ] = newname;
    99                                         ++level;
    100 
    101                                         ast::TypeDecl * decl = ast::mutate( td.get() );
    102                                         decl->name = newname;
    103                                         td = decl;
    104                                 }
    105                         }
    106                         return type;
    107                 }
    108 
    109                 template<typename NodeT>
    110                 const NodeT * closeLevel( const NodeT * type ) {
    111                         if ( !type->forall.empty() ) {
    112                                 nameMap.endScope();
    113                         }
    114                         return type;
     100                const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
     101                        if ( type->forall.empty() ) return type;
     102                        idMap.beginScope();
     103
     104                        // Load new names from this forall clause and perform renaming.
     105                        auto mutType = ast::shallowCopy( type );
     106                        // assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
     107                        for ( auto & td : mutType->forall ) {
     108                                auto mut = ast::shallowCopy( td.get() );
     109                                // assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
     110
     111                                if (mode == GEN_EXPR_ID) {
     112                                        mut->expr_id = next_expr_id;
     113                                        mut->formal_usage = -1;
     114                                        ++next_expr_id;
     115                                }
     116                                else if (mode == GEN_USAGE) {
     117                                        assertf(mut->expr_id, "unfilled expression id in generating candidate type");
     118                                        mut->formal_usage = next_usage_id;
     119                                }
     120                                else {
     121                                        assert(false);
     122                                }
     123                                idMap[ td->name ] = ast::TypeInstType::TypeEnvKey(*mut);
     124                               
     125                                td = mut;
     126                        }
     127
     128                        return mutType;
     129                }
     130
     131                void closeLevel( const ast::FunctionType * type ) {
     132                        if ( type->forall.empty() ) return;
     133                        idMap.endScope();
    115134                }
    116135        };
     
    119138        RenamingData renaming;
    120139
    121         struct RenameVars {
     140        struct RenameVars_old {
    122141                void previsit( TypeInstType * instType ) {
    123142                        renaming.openLevel( (Type*)instType );
     
    130149                        renaming.closeLevel( type );
    131150                }
     151        };
     152
     153        struct RenameVars_new : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
     154                RenameMode mode;
    132155
    133156                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
    134                         return renaming.openLevel( type );
    135                 }
     157                        return renaming.openLevel( type, mode );
     158                }
     159
     160                /*
    136161                const ast::StructInstType * previsit( const ast::StructInstType * type ) {
    137162                        return renaming.openLevel( type );
     
    143168                        return renaming.openLevel( type );
    144169                }
     170                */
     171
    145172                const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
    146                         return renaming.rename( renaming.openLevel( type ) );
    147                 }
    148                 const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) {
    149                         return renaming.closeLevel( type );
     173                        if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type
     174                        return renaming.rename( type );
     175                }
     176                void postvisit( const ast::FunctionType * type ) {
     177                        renaming.closeLevel( type );
    150178                }
    151179        };
     
    154182
    155183void renameTyVars( Type * t ) {
    156         PassVisitor<RenameVars> renamer;
     184        PassVisitor<RenameVars_old> renamer;
    157185        t->accept( renamer );
    158186}
    159187
    160 const ast::Type * renameTyVars( const ast::Type * t ) {
    161         ast::Pass<RenameVars> renamer;
     188const ast::Type * renameTyVars( const ast::Type * t, RenameMode mode, bool reset ) {
     189        // ast::Type *tc = ast::deepCopy(t);
     190        ast::Pass<RenameVars_new> renamer;
     191        renamer.core.mode = mode;
     192        if (mode == GEN_USAGE && reset) {
     193                renaming.nextUsage();
     194        }
    162195        return t->accept( renamer );
    163196}
     
    165198void resetTyVarRenaming() {
    166199        renaming.reset();
     200        renaming.nextUsage();
    167201}
    168202
  • src/ResolvExpr/RenameVars.h

    r3c64c668 r58fe85a  
    3030        /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
    3131        void renameTyVars( Type * );
    32         const ast::Type * renameTyVars( const ast::Type * );
     32
     33        enum RenameMode {
     34                GEN_USAGE, // for type in VariableExpr
     35                GEN_EXPR_ID // for type in decl
     36        };
     37        const ast::Type * renameTyVars( const ast::Type *, RenameMode mode = GEN_USAGE, bool reset = true );
     38       
    3339
    3440        /// resets internal state of renamer to avoid overflow
    3541        void resetTyVarRenaming();
     42
     43       
    3644} // namespace ResolvExpr
    3745
  • src/ResolvExpr/ResolvMode.h

    r3c64c668 r58fe85a  
    2222                const bool prune;            ///< Prune alternatives to min-cost per return type? [true]
    2323                const bool failFast;         ///< Fail on no resulting alternatives? [true]
    24                 const bool satisfyAssns;     ///< Satisfy assertions? [false]
    2524
    26         private:
    27                 constexpr ResolvMode(bool a, bool p, bool ff, bool sa)
    28                 : adjust(a), prune(p), failFast(ff), satisfyAssns(sa) {}
     25                constexpr ResolvMode(bool a, bool p, bool ff)
     26                : adjust(a), prune(p), failFast(ff) {}
    2927
    30         public:
    3128                /// Default settings
    32                 constexpr ResolvMode() : adjust(false), prune(true), failFast(true), satisfyAssns(false) {}
     29                constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
    3330               
    3431                /// With adjust flag set; turns array and function types into equivalent pointers
    35                 static constexpr ResolvMode withAdjustment() { return { true, true, true, false }; }
     32                static constexpr ResolvMode withAdjustment() { return { true, true, true }; }
    3633
    3734                /// With adjust flag set but prune unset; pruning ensures there is at least one alternative
    3835                /// per result type
    39                 static constexpr ResolvMode withoutPrune() { return { true, false, true, false }; }
     36                static constexpr ResolvMode withoutPrune() { return { true, false, true }; }
    4037
    4138                /// With adjust and prune flags set but failFast unset; failFast ensures there is at least
    4239                /// one resulting alternative
    43                 static constexpr ResolvMode withoutFailFast() { return { true, true, false, false }; }
     40                static constexpr ResolvMode withoutFailFast() { return { true, true, false }; }
    4441
    4542                /// The same mode, but with satisfyAssns turned on; for top-level calls
    46                 ResolvMode atTopLevel() const { return { adjust, prune, failFast, true }; }
     43                ResolvMode atTopLevel() const { return { adjust, true, failFast }; }
    4744        };
    4845} // namespace ResolvExpr
  • src/ResolvExpr/ResolveAssertions.cc

    r3c64c668 r58fe85a  
    277277                        const DeclarationWithType * candidate = cdata.id;
    278278
    279                         // build independent unification context for candidate
     279                        // ignore deleted candidates.
     280                        // NOTE: this behavior is different from main resolver.
     281                        // further investigations might be needed to determine
     282                        // if we should implement the same rule here
     283                        // (i.e. error if unique best match is deleted)
     284                        if (candidate->isDeleted) continue;
     285
     286                        // build independent unification context. for candidate
    280287                        AssertionSet have, newNeed;
    281288                        TypeEnvironment newEnv{ resn.alt.env };
     
    390397
    391398        /// Limit to depth of recursion of assertion satisfaction
    392         static const int recursionLimit = 4;
     399        static const int recursionLimit = 7;
    393400        /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of
    394401        static const int deferLimit = 10;
  • src/ResolvExpr/ResolveTypeof.cc

    r3c64c668 r58fe85a  
    1515
    1616#include "ResolveTypeof.h"
     17#include "RenameVars.h"
    1718
    1819#include <cassert>               // for assert
     
    2930#include "SynTree/Mutator.h"     // for Mutator
    3031#include "SynTree/Type.h"        // for TypeofType, Type
     32#include "SymTab/Mangler.h"
     33#include "InitTweak/InitTweak.h" // for isConstExpr
    3134
    3235namespace SymTab {
     
    99102                        // replace basetypeof(<enum>) by int
    100103                        if ( dynamic_cast<EnumInstType*>(newType) ) {
    101                                 Type* newerType = 
    102                                         new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 
     104                                Type* newerType =
     105                                        new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
    103106                                        newType->attributes };
    104107                                delete newType;
    105108                                newType = newerType;
    106109                        }
    107                         newType->get_qualifiers().val 
     110                        newType->get_qualifiers().val
    108111                                = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
    109112                } else {
    110113                        newType->get_qualifiers().val |= oldQuals;
    111114                }
    112                
     115
    113116                return newType;
    114117        }
     
    120123                ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {}
    121124
    122                 void premutate( const ast::TypeofType * ) { visit_children = false; }
    123 
    124                 const ast::Type * postmutate( const ast::TypeofType * typeofType ) {
     125                void previsit( const ast::TypeofType * ) { visit_children = false; }
     126
     127                const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
    125128                        // pass on null expression
    126129                        if ( ! typeofType->expr ) return typeofType;
     
    133136                                // typeof wrapping expression
    134137                                ast::TypeEnvironment dummy;
    135                                 ast::ptr< ast::Expr > newExpr = 
     138                                ast::ptr< ast::Expr > newExpr =
    136139                                        resolveInVoidContext( typeofType->expr, localSymtab, dummy );
    137140                                assert( newExpr->result && ! newExpr->result->isVoid() );
     
    143146                                // replace basetypeof(<enum>) by int
    144147                                if ( newType.as< ast::EnumInstType >() ) {
    145                                         newType = new ast::BasicType{ 
     148                                        newType = new ast::BasicType{
    146149                                                ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) };
    147150                                }
    148                                 reset_qualifiers( 
    149                                         newType, 
     151                                reset_qualifiers(
     152                                        newType,
    150153                                        ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
    151154                        } else {
     
    153156                        }
    154157
    155                         return newType;
     158                        return newType.release();
    156159                }
    157160        };
     
    161164        ast::Pass< ResolveTypeof_new > mutator{ symtab };
    162165        return type->accept( mutator );
     166}
     167
     168struct FixArrayDimension {
     169        // should not require a mutable symbol table - prevent pass template instantiation
     170        const ast::SymbolTable & _symtab;
     171        FixArrayDimension(const ast::SymbolTable & symtab): _symtab(symtab) {}
     172
     173        const ast::ArrayType * previsit (const ast::ArrayType * arrayType) {
     174                if (!arrayType->dimension) return arrayType;
     175                auto mutType = mutate(arrayType);
     176                ast::ptr<ast::Type> sizetype = ast::sizeType ? ast::sizeType : new ast::BasicType(ast::BasicType::LongUnsignedInt);
     177                mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, _symtab);
     178
     179                if (InitTweak::isConstExpr(mutType->dimension)) {
     180                        mutType->isVarLen = ast::LengthFlag::FixedLen;
     181                }
     182                else {
     183                        mutType->isVarLen = ast::LengthFlag::VariableLen;
     184                }
     185                return mutType;
     186        }
     187};
     188
     189const ast::Type * fixArrayType( const ast::Type * type, const ast::SymbolTable & symtab) {
     190        ast::Pass<FixArrayDimension> visitor {symtab};
     191        return type->accept(visitor);
     192}
     193
     194const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab ) {
     195        if (!decl->isTypeFixed) {
     196                auto mutDecl = mutate(decl);
     197                auto resolvedType = resolveTypeof(decl->type, symtab);
     198                resolvedType = fixArrayType(resolvedType, symtab);
     199                mutDecl->type = resolvedType;
     200
     201                // check variable length if object is an array.
     202                // xxx - should this be part of fixObjectType?
     203
     204                /*
     205                if (auto arrayType = dynamic_cast<const ast::ArrayType *>(resolvedType)) {
     206                        auto dimExpr = findSingleExpression(arrayType->dimension, ast::sizeType, symtab);
     207                        if (auto varexpr = arrayType->dimension.as<ast::VariableExpr>()) {// hoisted previously
     208                                if (InitTweak::isConstExpr(varexpr->var.strict_as<ast::ObjectDecl>()->init)) {
     209                                        auto mutType = mutate(arrayType);
     210                                        mutType->isVarLen = ast::LengthFlag::VariableLen;
     211                                        mutDecl->type = mutType;
     212                                }
     213                        }
     214                }
     215                */
     216
     217
     218                if (!mutDecl->name.empty())
     219                        mutDecl->mangleName = Mangle::mangle(mutDecl); // do not mangle unnamed variables
     220               
     221                mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
     222                mutDecl->isTypeFixed = true;
     223                return mutDecl;
     224        }
     225        return decl;
    163226}
    164227
  • src/ResolvExpr/ResolveTypeof.h

    r3c64c668 r58fe85a  
    2323        class Type;
    2424        class SymbolTable;
     25        class ObjectDecl;
    2526}
    2627
     
    2829        Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
    2930        const ast::Type * resolveTypeof( const ast::Type *, const ast::SymbolTable & );
     31        const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab );
    3032} // namespace ResolvExpr
    3133
  • src/ResolvExpr/Resolver.cc

    r3c64c668 r58fe85a  
    99// Author           : Aaron B. Moss
    1010// Created On       : Sun May 17 12:17:01 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Wed May 29 11:00:00 2019
    13 // Update Count     : 241
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Mar 27 11:58:00 2020
     13// Update Count     : 242
    1414//
    1515
     
    2626#include "RenameVars.h"                  // for RenameVars, global_renamer
    2727#include "Resolver.h"
     28#include "ResolveTypeof.h"
    2829#include "ResolvMode.h"                  // for ResolvMode
    2930#include "typeops.h"                     // for extractResultType
    3031#include "Unify.h"                       // for unify
     32#include "CompilationState.h"
    3133#include "AST/Chain.hpp"
    3234#include "AST/Decl.hpp"
     
    3840#include "Common/PassVisitor.h"          // for PassVisitor
    3941#include "Common/SemanticError.h"        // for SemanticError
     42#include "Common/Stats/ResolveTime.h"    // for ResolveTime::start(), ResolveTime::stop()
    4043#include "Common/utility.h"              // for ValueGuard, group_iterate
    4144#include "InitTweak/GenInit.h"
     
    4447#include "SymTab/Autogen.h"              // for SizeType
    4548#include "SymTab/Indexer.h"              // for Indexer
     49#include "SymTab/Mangler.h"              // for Mangler
    4650#include "SynTree/Declaration.h"         // for ObjectDecl, TypeDecl, Declar...
    4751#include "SynTree/Expression.h"          // for Expression, CastExpr, InitExpr
     
    560564                // TODO: Replace *exception type with &exception type.
    561565                if ( throwStmt->get_expr() ) {
    562                         const StructDecl * exception_decl = indexer.lookupStruct( "__cfaabi_ehm__base_exception_t" );
     566                        const StructDecl * exception_decl = indexer.lookupStruct( "__cfaehm_base_exception_t" );
    563567                        assert( exception_decl );
    564568                        Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
     
    964968        namespace {
    965969                /// Finds deleted expressions in an expression tree
    966                 struct DeleteFinder_new final : public ast::WithShortCircuiting {
    967                         const ast::DeletedExpr * delExpr = nullptr;
     970                struct DeleteFinder_new final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder_new> {
     971                        const ast::DeletedExpr * result = nullptr;
    968972
    969973                        void previsit( const ast::DeletedExpr * expr ) {
    970                                 if ( delExpr ) { visit_children = false; }
    971                                 else { delExpr = expr; }
    972                         }
    973 
    974                         void previsit( const ast::Expr * ) {
    975                                 if ( delExpr ) { visit_children = false; }
     974                                if ( result ) { visit_children = false; }
     975                                else { result = expr; }
     976                        }
     977
     978                        void previsit( const ast::Expr * expr ) {
     979                                if ( result ) { visit_children = false; }
     980                                if (expr->inferred.hasParams()) {
     981                                        for (auto & imp : expr->inferred.inferParams() ) {
     982                                                imp.second.expr->accept(*visitor);
     983                                        }
     984                                }
    976985                        }
    977986                };
    978987        } // anonymous namespace
    979 
    980988        /// Check if this expression is or includes a deleted expression
    981989        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
    982                 ast::Pass<DeleteFinder_new> finder;
    983                 expr->accept( finder );
    984                 return finder.pass.delExpr;
     990                return ast::Pass<DeleteFinder_new>::read( expr );
    985991        }
    986992
     
    10721078                /// Strips extraneous casts out of an expression
    10731079                struct StripCasts_new final {
    1074                         const ast::Expr * postmutate( const ast::CastExpr * castExpr ) {
     1080                        const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
    10751081                                if (
    1076                                         castExpr->isGenerated
     1082                                        castExpr->isGenerated == ast::GeneratedCast
    10771083                                        && typesCompatible( castExpr->arg->result, castExpr->result )
    10781084                                ) {
     
    11061112                }
    11071113
    1108                 /// Establish post-resolver invariants for expressions
     1114               
     1115        } // anonymous namespace
     1116/// Establish post-resolver invariants for expressions
    11091117                void finishExpr(
    11101118                        ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
     
    11191127                        StripCasts_new::strip( expr );
    11201128                }
    1121         } // anonymous namespace
    1122 
    11231129
    11241130        ast::ptr< ast::Expr > resolveInVoidContext(
     
    11281134
    11291135                // set up and resolve expression cast to void
    1130                 ast::CastExpr * untyped = new ast::CastExpr{ expr };
     1136                ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
    11311137                CandidateRef choice = findUnfinishedKindExpression(
    11321138                        untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
     
    11401146        }
    11411147
    1142         namespace {
    1143                 /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
     1148        /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
    11441149                /// context.
    11451150                ast::ptr< ast::Expr > findVoidExpression(
    11461151                        const ast::Expr * untyped, const ast::SymbolTable & symtab
    11471152                ) {
    1148                         resetTyVarRenaming();
    11491153                        ast::TypeEnvironment env;
    11501154                        ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env );
     
    11521156                        return newExpr;
    11531157                }
     1158
     1159        namespace {
     1160               
    11541161
    11551162                /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
     
    11631170                        CandidateRef choice =
    11641171                                findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
    1165                         finishExpr( choice->expr, choice->env, untyped->env );
     1172                        ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
    11661173                        return std::move( choice->expr );
    11671174                }
     
    11711178                        const ast::Expr * untyped, const ast::SymbolTable & symtab
    11721179                ) {
    1173                         return findKindExpression( untyped, symtab );
     1180                        Stats::ResolveTime::start( untyped );
     1181                        auto res = findKindExpression( untyped, symtab );
     1182                        Stats::ResolveTime::stop();
     1183                        return res;
    11741184                }
    11751185        } // anonymous namespace
    11761186
    1177                 ast::ptr< ast::Expr > findSingleExpression(
    1178                         const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
    1179                 ) {
    1180                         assert( untyped && type );
    1181                         ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
    1182                         ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
    1183                         removeExtraneousCast( newExpr, symtab );
    1184                         return newExpr;
    1185                 }
     1187        ast::ptr< ast::Expr > findSingleExpression(
     1188                const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
     1189        ) {
     1190                assert( untyped && type );
     1191                ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
     1192                ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
     1193                removeExtraneousCast( newExpr, symtab );
     1194                return newExpr;
     1195        }
    11861196
    11871197        namespace {
     1198                bool structOrUnion( const Candidate & i ) {
     1199                        const ast::Type * t = i.expr->result->stripReferences();
     1200                        return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
     1201                }
    11881202                /// Predicate for "Candidate has integral type"
    11891203                bool hasIntegralType( const Candidate & i ) {
     
    12211235                template<typename Iter>
    12221236                inline bool nextMutex( Iter & it, const Iter & end ) {
    1223                         while ( it != end && ! (*it)->get_type()->is_mutex() ) { ++it; }
     1237                        while ( it != end && ! (*it)->is_mutex() ) { ++it; }
    12241238                        return it != end;
    12251239                }
     
    12331247                ast::ptr< ast::Type > functionReturn = nullptr;
    12341248                ast::CurrentObject currentObject;
     1249                // for work previously in GenInit
     1250                static InitTweak::ManagedTypes_new managedTypes;
     1251
    12351252                bool inEnumDecl = false;
    12361253
    12371254        public:
     1255                static size_t traceId;
    12381256                Resolver_new() = default;
    12391257                Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
    12401258
    1241                 void previsit( const ast::FunctionDecl * );
     1259                const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
    12421260                const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
    1243                 void previsit( const ast::ObjectDecl * );
     1261                const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
     1262                void previsit( const ast::AggregateDecl * );
     1263                void previsit( const ast::StructDecl * );
    12441264                void previsit( const ast::EnumDecl * );
    12451265                const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
     
    12601280                const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
    12611281                const ast::CatchStmt *       previsit( const ast::CatchStmt * );
     1282                const ast::CatchStmt *       postvisit( const ast::CatchStmt * );
    12621283                const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
     1284                const ast::WithStmt *        previsit( const ast::WithStmt * );
    12631285
    12641286                const ast::SingleInit *      previsit( const ast::SingleInit * );
    12651287                const ast::ListInit *        previsit( const ast::ListInit * );
    12661288                const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
     1289
     1290                void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
     1291
     1292                void beginScope() { managedTypes.beginScope(); }
     1293                void endScope() { managedTypes.endScope(); }
     1294                bool on_error(ast::ptr<ast::Decl> & decl);
    12671295        };
    1268 
    1269         void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) {
    1270                 ast::Pass< Resolver_new > resolver;
    1271                 accept_all( translationUnit, resolver );
     1296        // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
     1297
     1298        InitTweak::ManagedTypes_new Resolver_new::managedTypes;
     1299
     1300        void resolve( ast::TranslationUnit& translationUnit ) {
     1301                ast::Pass< Resolver_new >::run( translationUnit );
    12721302        }
    12731303
     
    12801310        }
    12811311
    1282         ast::ptr< ast::Expr > resolveStmtExpr(
     1312        const ast::Expr * resolveStmtExpr(
    12831313                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab
    12841314        ) {
    12851315                assert( stmtExpr );
    12861316                ast::Pass< Resolver_new > resolver{ symtab };
    1287                 ast::ptr< ast::Expr > ret = stmtExpr;
    1288                 ret = ret->accept( resolver );
    1289                 strict_dynamic_cast< ast::StmtExpr * >( ret.get_and_mutate() )->computeResult();
     1317                auto ret = mutate(stmtExpr->accept(resolver));
     1318                strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
    12901319                return ret;
    12911320        }
    12921321
    1293         void Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
     1322        namespace {
     1323                const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ast::SymbolTable & symtab) {
     1324                        std::string name = attr->normalizedName();
     1325                        if (name == "constructor" || name == "destructor") {
     1326                                if (attr->params.size() == 1) {
     1327                                        auto arg = attr->params.front();
     1328                                        auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), symtab );
     1329                                        auto result = eval(arg);
     1330
     1331                                        auto mutAttr = mutate(attr);
     1332                                        mutAttr->params.front() = resolved;
     1333                                        if (! result.second) {
     1334                                                SemanticWarning(loc, Warning::GccAttributes,
     1335                                                        toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
     1336                                        }
     1337                                        else {
     1338                                                auto priority = result.first;
     1339                                                if (priority < 101) {
     1340                                                        SemanticWarning(loc, Warning::GccAttributes,
     1341                                                                toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
     1342                                                } else if (priority < 201 && ! buildingLibrary()) {
     1343                                                        SemanticWarning(loc, Warning::GccAttributes,
     1344                                                                toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
     1345                                                }
     1346                                        }
     1347                                        return mutAttr;
     1348                                } else if (attr->params.size() > 1) {
     1349                                        SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
     1350                                } else {
     1351                                        SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
     1352                                }
     1353                        }
     1354                        return attr;
     1355                }
     1356        }
     1357
     1358        const ast::FunctionDecl * Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
    12941359                GuardValue( functionReturn );
     1360
     1361                assert (functionDecl->unique());
     1362                if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
     1363                        SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
     1364                }
     1365
     1366                if (!functionDecl->isTypeFixed) {
     1367                        auto mutDecl = mutate(functionDecl);
     1368                        auto mutType = mutDecl->type.get_and_mutate();
     1369
     1370                        for (auto & attr: mutDecl->attributes) {
     1371                                attr = handleAttribute(mutDecl->location, attr, symtab);
     1372                        }
     1373
     1374                        // handle assertions
     1375
     1376                        symtab.enterScope();
     1377                        mutType->forall.clear();
     1378                        mutType->assertions.clear();
     1379                        for (auto & typeParam : mutDecl->type_params) {
     1380                                symtab.addType(typeParam);
     1381                                mutType->forall.emplace_back(new ast::TypeInstType(typeParam->name, typeParam));
     1382                        }
     1383                        for (auto & asst : mutDecl->assertions) {
     1384                                asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
     1385                                symtab.addId(asst);
     1386                                mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
     1387                        }
     1388
     1389                        // temporarily adds params to symbol table.
     1390                        // actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
     1391
     1392                        std::vector<ast::ptr<ast::Type>> paramTypes;
     1393                        std::vector<ast::ptr<ast::Type>> returnTypes;
     1394
     1395                        for (auto & param : mutDecl->params) {
     1396                                param = fixObjectType(param.strict_as<ast::ObjectDecl>(), symtab);
     1397                                symtab.addId(param);
     1398                                paramTypes.emplace_back(param->get_type());
     1399                        }
     1400                        for (auto & ret : mutDecl->returns) {
     1401                                ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), symtab);
     1402                                returnTypes.emplace_back(ret->get_type());
     1403                        }
     1404                        // since function type in decl is just a view of param types, need to update that as well
     1405                        mutType->params = std::move(paramTypes);
     1406                        mutType->returns = std::move(returnTypes);
     1407
     1408                        auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
     1409
     1410                        std::list<ast::ptr<ast::Stmt>> newStmts;
     1411                        resolveWithExprs (mutDecl->withExprs, newStmts);
     1412
     1413                        if (mutDecl->stmts) {
     1414                                auto mutStmt = mutDecl->stmts.get_and_mutate();
     1415                                mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
     1416                                mutDecl->stmts = mutStmt;
     1417                        }
     1418
     1419                        symtab.leaveScope();
     1420
     1421                        mutDecl->type = renamedType;
     1422                        mutDecl->mangleName = Mangle::mangle(mutDecl);
     1423                        mutDecl->isTypeFixed = true;
     1424                        functionDecl = mutDecl;
     1425                }
     1426                managedTypes.handleDWT(functionDecl);
     1427
    12951428                functionReturn = extractResultType( functionDecl->type );
     1429                return functionDecl;
    12961430        }
    12971431
     
    12991433                // default value expressions have an environment which shouldn't be there and trips up
    13001434                // later passes.
    1301                 ast::ptr< ast::FunctionDecl > ret = functionDecl;
    1302                 for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {
    1303                         const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i];
    1304 
    1305                         if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {
     1435                assert( functionDecl->unique() );
     1436                ast::FunctionType * mutType = mutate( functionDecl->type.get() );
     1437
     1438                for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
     1439                        if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
    13061440                                if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
    13071441                                        if ( init->value->env == nullptr ) continue;
    13081442                                        // clone initializer minus the initializer environment
    1309                                         ast::chain_mutate( ret )
    1310                                                 ( &ast::FunctionDecl::type )
    1311                                                         ( &ast::FunctionType::params )[i]
    1312                                                                 ( &ast::ObjectDecl::init )
    1313                                                                         ( &ast::SingleInit::value )->env = nullptr;
    1314 
    1315                                         assert( functionDecl != ret.get() || functionDecl->unique() );
    1316                                         assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env );
     1443                                        auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
     1444                                        auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
     1445                                        auto mutValue = mutate( mutInit->value.get() );
     1446
     1447                                        mutValue->env = nullptr;
     1448                                        mutInit->value = mutValue;
     1449                                        mutParam->init = mutInit;
     1450                                        mutType->params[i] = mutParam;
     1451
     1452                                        assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
    13171453                                }
    13181454                        }
    13191455                }
    1320                 return ret.get();
    1321         }
    1322 
    1323         void Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
     1456                mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
     1457                return functionDecl;
     1458        }
     1459
     1460        const ast::ObjectDecl * Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
    13241461                // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
    13251462                // class-variable `initContext` is changed multiple times because the LHS is analyzed
     
    13291466                // selecting the RHS.
    13301467                GuardValue( currentObject );
    1331                 currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
     1468
    13321469                if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
    13331470                        // enumerator initializers should not use the enum type to initialize, since the
    13341471                        // enum type is still incomplete at this point. Use `int` instead.
     1472                        objectDecl = fixObjectType(objectDecl, symtab);
    13351473                        currentObject = ast::CurrentObject{
    13361474                                objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
    13371475                }
     1476                else {
     1477                        if (!objectDecl->isTypeFixed) {
     1478                                auto newDecl = fixObjectType(objectDecl, symtab);
     1479                                auto mutDecl = mutate(newDecl);
     1480
     1481                                // generate CtorInit wrapper when necessary.
     1482                                // in certain cases, fixObjectType is called before reaching
     1483                                // this object in visitor pass, thus disabling CtorInit codegen.
     1484                                // this happens on aggregate members and function parameters.
     1485                                if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
     1486                                        // constructed objects cannot be designated
     1487                                        if ( InitTweak::isDesignated( mutDecl->init ) ) SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
     1488                                        // constructed objects should not have initializers nested too deeply
     1489                                        if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
     1490
     1491                                        mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
     1492                                }
     1493
     1494                                objectDecl = mutDecl;
     1495                        }
     1496                        currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
     1497                }
     1498
     1499                return objectDecl;
     1500        }
     1501
     1502        void Resolver_new::previsit( const ast::AggregateDecl * _aggDecl ) {
     1503                auto aggDecl = mutate(_aggDecl);
     1504                assertf(aggDecl == _aggDecl, "type declarations must be unique");
     1505
     1506                for (auto & member: aggDecl->members) {
     1507                        // nested type decls are hoisted already. no need to do anything
     1508                        if (auto obj = member.as<ast::ObjectDecl>()) {
     1509                                member = fixObjectType(obj, symtab);
     1510                        }
     1511                }
     1512        }
     1513
     1514        void Resolver_new::previsit( const ast::StructDecl * structDecl ) {
     1515                previsit(static_cast<const ast::AggregateDecl *>(structDecl));
     1516                managedTypes.handleStruct(structDecl);
    13381517        }
    13391518
     
    13411520                // in case we decide to allow nested enums
    13421521                GuardValue( inEnumDecl );
    1343                 inEnumDecl = false;
    1344         }
     1522                inEnumDecl = true;
     1523                // don't need to fix types for enum fields
     1524        }
     1525
    13451526
    13461527        const ast::StaticAssertDecl * Resolver_new::previsit(
     
    13551536        const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) {
    13561537                if ( type->dimension ) {
    1357                         #warning should use new equivalent to Validate::SizeType rather than sizeType here
    1358                         ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt };
     1538                        ast::ptr< ast::Type > sizeType = ast::sizeType;
    13591539                        ast::mutate_field(
    13601540                                type, &PtrType::dimension,
     
    14771657                if ( throwStmt->expr ) {
    14781658                        const ast::StructDecl * exceptionDecl =
    1479                                 symtab.lookupStruct( "__cfaabi_ehm__base_exception_t" );
     1659                                symtab.lookupStruct( "__cfaehm_base_exception_t" );
    14801660                        assert( exceptionDecl );
    14811661                        ast::ptr< ast::Type > exceptType =
     
    14891669
    14901670        const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
    1491                 // TODO: This will need a fix for the decl/cond scoping problem.
     1671                // Until we are very sure this invarent (ifs that move between passes have thenPart)
     1672                // holds, check it. This allows a check for when to decode the mangling.
     1673                if ( auto ifStmt = catchStmt->body.as<ast::IfStmt>() ) {
     1674                        assert( ifStmt->thenPart );
     1675                }
     1676                // Encode the catchStmt so the condition can see the declaration.
    14921677                if ( catchStmt->cond ) {
    1493                         ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool };
    1494                         catchStmt = ast::mutate_field(
    1495                                 catchStmt, &ast::CatchStmt::cond,
    1496                                 findSingleExpression( catchStmt->cond, boolType, symtab ) );
     1678                        ast::CatchStmt * stmt = mutate( catchStmt );
     1679                        stmt->body = new ast::IfStmt( stmt->location, stmt->cond, nullptr, stmt->body );
     1680                        stmt->cond = nullptr;
     1681                        return stmt;
     1682                }
     1683                return catchStmt;
     1684        }
     1685
     1686        const ast::CatchStmt * Resolver_new::postvisit( const ast::CatchStmt * catchStmt ) {
     1687                // Decode the catchStmt so everything is stored properly.
     1688                const ast::IfStmt * ifStmt = catchStmt->body.as<ast::IfStmt>();
     1689                if ( nullptr != ifStmt && nullptr == ifStmt->thenPart ) {
     1690                        assert( ifStmt->cond );
     1691                        assert( ifStmt->elsePart );
     1692                        ast::CatchStmt * stmt = ast::mutate( catchStmt );
     1693                        stmt->cond = ifStmt->cond;
     1694                        stmt->body = ifStmt->elsePart;
     1695                        // ifStmt should be implicately deleted here.
     1696                        return stmt;
    14971697                }
    14981698                return catchStmt;
     
    16111811                                                                // Check if the argument matches the parameter type in the current
    16121812                                                                // scope
    1613                                                                 ast::ptr< ast::Type > paramType = (*param)->get_type();
     1813                                                                // ast::ptr< ast::Type > paramType = (*param)->get_type();
    16141814                                                                if (
    16151815                                                                        ! unify(
    1616                                                                                 arg->expr->result, paramType, resultEnv, need, have, open,
     1816                                                                                arg->expr->result, *param, resultEnv, need, have, open,
    16171817                                                                                symtab )
    16181818                                                                ) {
     
    16211821                                                                        ss << "candidate function not viable: no known conversion "
    16221822                                                                                "from '";
    1623                                                                         ast::print( ss, (*param)->get_type() );
     1823                                                                        ast::print( ss, *param );
    16241824                                                                        ss << "' to '";
    16251825                                                                        ast::print( ss, arg->expr->result );
     
    17511951        }
    17521952
     1953        const ast::WithStmt * Resolver_new::previsit( const ast::WithStmt * withStmt ) {
     1954                auto mutStmt = mutate(withStmt);
     1955                resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
     1956                return mutStmt;
     1957        }
     1958
     1959        void Resolver_new::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
     1960                for (auto & expr : exprs) {
     1961                        // only struct- and union-typed expressions are viable candidates
     1962                        expr = findKindExpression( expr, symtab, structOrUnion, "with expression" );
     1963
     1964                        // if with expression might be impure, create a temporary so that it is evaluated once
     1965                        if ( Tuples::maybeImpure( expr ) ) {
     1966                                static UniqueName tmpNamer( "_with_tmp_" );
     1967                                const CodeLocation loc = expr->location;
     1968                                auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
     1969                                expr = new ast::VariableExpr( loc, tmp );
     1970                                stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
     1971                                if ( InitTweak::isConstructable( tmp->type ) ) {
     1972                                        // generate ctor/dtor and resolve them
     1973                                        tmp->init = InitTweak::genCtorInit( loc, tmp );
     1974                                }
     1975                                // since tmp is freshly created, this should modify tmp in-place
     1976                                tmp->accept( *visitor );
     1977                        }
     1978                }
     1979        }
    17531980
    17541981
     
    18462073        }
    18472074
     2075        // suppress error on autogen functions and mark invalid autogen as deleted.
     2076        bool Resolver_new::on_error(ast::ptr<ast::Decl> & decl) {
     2077                if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
     2078                        // xxx - can intrinsic gen ever fail?
     2079                        if (functionDecl->linkage == ast::Linkage::AutoGen) {
     2080                                auto mutDecl = mutate(functionDecl);
     2081                                mutDecl->isDeleted = true;
     2082                                mutDecl->stmts = nullptr;
     2083                                decl = mutDecl;
     2084                                return false;
     2085                        }
     2086                }
     2087                return true;
     2088        }
     2089
    18482090} // namespace ResolvExpr
    18492091
  • src/ResolvExpr/Resolver.h

    r3c64c668 r58fe85a  
    3535        class StmtExpr;
    3636        class SymbolTable;
     37        struct TranslationUnit;
    3738        class Type;
    3839        class TypeEnvironment;
     
    5556
    5657        /// Checks types and binds syntactic constructs to typed representations
    57         void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );
     58        void resolve( ast::TranslationUnit& translationUnit );
    5859        /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
    5960        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
     
    6263        ast::ptr< ast::Expr > resolveInVoidContext(
    6364                const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env );
    64         /// Resolve `untyped` to the single expression whose candidate is the best match for the 
     65        /// Resolve `untyped` to the single expression whose candidate is the best match for the
    6566        /// given type.
    6667        ast::ptr< ast::Expr > findSingleExpression(
    6768                const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab );
     69        ast::ptr< ast::Expr > findVoidExpression(
     70                const ast::Expr * untyped, const ast::SymbolTable & symtab);
    6871        /// Resolves a constructor init expression
    69         ast::ptr< ast::Init > resolveCtorInit( 
     72        ast::ptr< ast::Init > resolveCtorInit(
    7073                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
    71         /// Resolves a statement expression
    72         ast::ptr< ast::Expr > resolveStmtExpr(
     74        /// Resolves a statement expression 
     75        const ast::Expr * resolveStmtExpr(
    7376                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab );
    7477} // namespace ResolvExpr
  • src/ResolvExpr/SatisfyAssertions.cpp

    r3c64c668 r58fe85a  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon Jun 10 17:45:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Mon Jun 10 17:45:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct  1 13:56:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    5757                ast::UniqueId resnSlot;          ///< Slot for any recursive assertion IDs
    5858
    59                 AssnCandidate( 
    60                         const ast::SymbolTable::IdData c, const ast::Type * at, ast::TypeEnvironment && e, 
     59                AssnCandidate(
     60                        const ast::SymbolTable::IdData c, const ast::Type * at, ast::TypeEnvironment && e,
    6161                        ast::AssertionSet && h, ast::AssertionSet && n, ast::OpenVarSet && o, ast::UniqueId rs )
    62                 : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ), 
     62                : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ),
    6363                  need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {}
    6464        };
     
    6969        /// Reference to a single deferred item
    7070        struct DeferRef {
    71                 const ast::DeclWithType * decl;
     71                const ast::VariableExpr * expr;
    7272                const ast::AssertionSetValue & info;
    7373                const AssnCandidate & match;
    7474        };
    75        
    76         /// Wrapper for the deferred items from a single assertion satisfaction. 
     75
     76        /// Wrapper for the deferred items from a single assertion satisfaction.
    7777        /// Acts like an indexed list of DeferRef
    7878        struct DeferItem {
    79                 const ast::DeclWithType * decl;
     79                const ast::VariableExpr * expr;
    8080                const ast::AssertionSetValue & info;
    8181                AssnCandidateList matches;
    8282
    83                 DeferItem( 
    84                         const ast::DeclWithType * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
    85                 : decl( d ), info( i ), matches( std::move( ms ) ) {}
     83                DeferItem(
     84                        const ast::VariableExpr * d, const ast::AssertionSetValue & i, AssnCandidateList && ms )
     85                : expr( d ), info( i ), matches( std::move( ms ) ) {}
    8686
    8787                bool empty() const { return matches.empty(); }
     
    8989                AssnCandidateList::size_type size() const { return matches.size(); }
    9090
    91                 DeferRef operator[] ( unsigned i ) const { return { decl, info, matches[i] }; }
     91                DeferRef operator[] ( unsigned i ) const { return { expr, info, matches[i] }; }
    9292        };
    9393
     
    117117                /// Initial satisfaction state for a candidate
    118118                SatState( CandidateRef & c, const ast::SymbolTable & syms )
    119                 : cand( c ), need(), newNeed(), deferred(), inferred(), costs{ Cost::zero }, 
     119                : cand( c ), need(), newNeed(), deferred(), inferred(), costs{ Cost::zero },
    120120                  symtab( syms ) { need.swap( c->need ); }
    121                
     121
    122122                /// Update satisfaction state for next step after previous state
    123123                SatState( SatState && o, IterateFlag )
    124                 : cand( std::move( o.cand ) ), need( o.newNeed.begin(), o.newNeed.end() ), newNeed(), 
    125                   deferred(), inferred( std::move( o.inferred ) ), costs( std::move( o.costs ) ), 
     124                : cand( std::move( o.cand ) ), need( o.newNeed.begin(), o.newNeed.end() ), newNeed(),
     125                  deferred(), inferred( std::move( o.inferred ) ), costs( std::move( o.costs ) ),
    126126                  symtab( o.symtab ) { costs.emplace_back( Cost::zero ); }
    127                
     127
    128128                /// Field-wise next step constructor
    129129                SatState(
    130                         CandidateRef && c, ast::AssertionSet && nn, InferCache && i, CostVec && cs, 
     130                        CandidateRef && c, ast::AssertionSet && nn, InferCache && i, CostVec && cs,
    131131                        ast::SymbolTable && syms )
    132                 : cand( std::move( c ) ), need( nn.begin(), nn.end() ), newNeed(), deferred(), 
     132                : cand( std::move( c ) ), need( nn.begin(), nn.end() ), newNeed(), deferred(),
    133133                  inferred( std::move( i ) ), costs( std::move( cs ) ), symtab( std::move( syms ) )
    134134                  { costs.emplace_back( Cost::zero ); }
     
    138138        void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) {
    139139                for ( auto & i : have ) {
    140                         if ( i.second.isUsed ) { symtab.addId( i.first ); }
     140                        if ( i.second.isUsed ) { symtab.addId( i.first->var ); }
    141141                }
    142142        }
    143143
    144144        /// Binds a single assertion, updating satisfaction state
    145         void bindAssertion( 
    146                 const ast::DeclWithType * decl, const ast::AssertionSetValue & info, CandidateRef & cand,
     145        void bindAssertion(
     146                const ast::VariableExpr * expr, const ast::AssertionSetValue & info, CandidateRef & cand,
    147147                AssnCandidate & match, InferCache & inferred
    148148        ) {
    149149                const ast::DeclWithType * candidate = match.cdata.id;
    150                 assertf( candidate->uniqueId, 
     150                assertf( candidate->uniqueId,
    151151                        "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
    152                
     152
    153153                ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cvtCost );
    154154                varExpr->result = match.adjType;
     
    156156
    157157                // place newly-inferred assertion in proper location in cache
    158                 inferred[ info.resnSlot ][ decl->uniqueId ] = ast::ParamEntry{
    159                         candidate->uniqueId, candidate, match.adjType, decl->get_type(), varExpr };
     158                inferred[ info.resnSlot ][ expr->var->uniqueId ] = ast::ParamEntry{
     159                        candidate->uniqueId, candidate, match.adjType, expr->result, varExpr };
    160160        }
    161161
     
    167167                // find candidates that unify with the desired type
    168168                AssnCandidateList matches;
    169                 for ( const ast::SymbolTable::IdData & cdata : sat.symtab.lookupId( assn.first->name ) ) {
     169
     170                std::vector<ast::SymbolTable::IdData> candidates;
     171                auto kind = ast::SymbolTable::getSpecialFunctionKind(assn.first->var->name);
     172                if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
     173                        // prefilter special decls by argument type, if already known
     174                        ast::ptr<ast::Type> thisArgType = assn.first->result.strict_as<ast::PointerType>()->base
     175                                .strict_as<ast::FunctionType>()->params[0]
     176                                .strict_as<ast::ReferenceType>()->base;
     177                        sat.cand->env.apply(thisArgType);
     178
     179                        std::string otypeKey = "";
     180                        if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer;
     181                        else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams);
     182
     183                        candidates = sat.symtab.specialLookupId(kind, otypeKey);
     184                }
     185                else {
     186                        candidates = sat.symtab.lookupId(assn.first->var->name);
     187                }
     188                for ( const ast::SymbolTable::IdData & cdata : candidates ) {
    170189                        const ast::DeclWithType * candidate = cdata.id;
     190
     191                        // ignore deleted candidates.
     192                        // NOTE: this behavior is different from main resolver.
     193                        // further investigations might be needed to determine
     194                        // if we should implement the same rule here
     195                        // (i.e. error if unique best match is deleted)
     196                        if (candidate->isDeleted && candidate->linkage == ast::Linkage::AutoGen) continue;
    171197
    172198                        // build independent unification context for candidate
     
    174200                        ast::TypeEnvironment newEnv{ sat.cand->env };
    175201                        ast::OpenVarSet newOpen{ sat.cand->open };
    176                         ast::ptr< ast::Type > toType = assn.first->get_type();
    177                         ast::ptr< ast::Type > adjType = 
    178                                 renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ) );
     202                        ast::ptr< ast::Type > toType = assn.first->result;
     203                        ast::ptr< ast::Type > adjType =
     204                                renameTyVars( adjustExprType( candidate->get_type(), newEnv, sat.symtab ), GEN_USAGE, false );
    179205
    180206                        // only keep candidates which unify
     
    187213                                }
    188214
    189                                 matches.emplace_back( 
    190                                         cdata, adjType, std::move( newEnv ), std::move( newNeed ), std::move( have ),
     215                                matches.emplace_back(
     216                                        cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    191217                                        std::move( newOpen ), crntResnSlot );
    192218                        }
     
    229255                InferMatcher( InferCache & inferred ) : inferred( inferred ) {}
    230256
    231                 const ast::Expr * postmutate( const ast::Expr * expr ) {
     257                const ast::Expr * postvisit( const ast::Expr * expr ) {
    232258                        // Skip if no slots to find
    233                         if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
    234 
     259                        if ( !expr->inferred.hasSlots() ) return expr;
     260                        // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
     261                        std::vector<UniqueId> missingSlots;
    235262                        // find inferred parameters for resolution slots
    236                         ast::InferredParams newInferred;
     263                        ast::InferredParams * newInferred = new ast::InferredParams();
    237264                        for ( UniqueId slot : expr->inferred.resnSlots() ) {
    238265                                // fail if no matching assertions found
    239266                                auto it = inferred.find( slot );
    240267                                if ( it == inferred.end() ) {
    241                                         assert(!"missing assertion");
     268                                        // std::cerr << "missing assertion " << slot << std::endl;
     269                                        missingSlots.push_back(slot);
     270                                        continue;
    242271                                }
    243272
     
    245274                                for ( auto & entry : it->second ) {
    246275                                        // recurse on inferParams of resolved expressions
    247                                         entry.second.expr = postmutate( entry.second.expr );
    248                                         auto res = newInferred.emplace( entry );
     276                                        entry.second.expr = postvisit( entry.second.expr );
     277                                        auto res = newInferred->emplace( entry );
    249278                                        assert( res.second && "all assertions newly placed" );
    250279                                }
     
    252281
    253282                        ast::Expr * ret = mutate( expr );
    254                         ret->inferred.set_inferParams( std::move( newInferred ) );
     283                        ret->inferred.set_inferParams( newInferred );
     284                        if (!missingSlots.empty()) ret->inferred.resnSlots() = missingSlots;
    255285                        return ret;
    256286                }
    257287        };
    258288
    259         /// Replace ResnSlots with InferParams and add alternative to output list, if it meets pruning 
     289        /// Replace ResnSlots with InferParams and add alternative to output list, if it meets pruning
    260290        /// threshold.
    261         void finalizeAssertions( 
    262                 CandidateRef & cand, InferCache & inferred, PruneMap & thresholds, CostVec && costs, 
    263                 CandidateList & out 
     291        void finalizeAssertions(
     292                CandidateRef & cand, InferCache & inferred, PruneMap & thresholds, CostVec && costs,
     293                CandidateList & out
    264294        ) {
    265295                // prune if cheaper alternative for same key has already been generated
     
    278308        }
    279309
    280         /// Combo iterator that combines candidates into an output list, merging their environments. 
    281         /// Rejects an appended candidate if environments cannot be merged. See `Common/FilterCombos.h` 
     310        /// Combo iterator that combines candidates into an output list, merging their environments.
     311        /// Rejects an appended candidate if environments cannot be merged. See `Common/FilterCombos.h`
    282312        /// for description of "combo iterator".
    283313        class CandidateEnvMerger {
     
    299329                        Cost cost;
    300330
    301                         OutType( 
    302                                 const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
     331                        OutType(
     332                                const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
    303333                                const std::vector< DeferRef > & as, const ast::SymbolTable & symtab )
    304334                        : env( e ), open( o ), assns( as ), cost( Cost::zero ) {
     
    306336                                for ( const DeferRef & assn : assns ) {
    307337                                        // compute conversion cost from satisfying decl to assertion
    308                                         cost += computeConversionCost( 
    309                                                 assn.match.adjType, assn.decl->get_type(), symtab, env );
    310                                        
     338                                        cost += computeConversionCost(
     339                                                assn.match.adjType, assn.expr->result, false, symtab, env );
     340
    311341                                        // mark vars+specialization on function-type assertions
    312                                         const ast::FunctionType * func = 
     342                                        const ast::FunctionType * func =
    313343                                                GenPoly::getFunctionType( assn.match.cdata.id->get_type() );
    314344                                        if ( ! func ) continue;
    315345
    316                                         for ( const ast::DeclWithType * param : func->params ) {
    317                                                 cost.decSpec( specCost( param->get_type() ) );
     346                                        for ( const auto & param : func->params ) {
     347                                                cost.decSpec( specCost( param ) );
    318348                                        }
    319                                        
     349
    320350                                        cost.incVar( func->forall.size() );
    321                                        
    322                                         for ( const ast::TypeDecl * td : func->forall ) {
    323                                                 cost.decSpec( td->assertions.size() );
    324                                         }
     351
     352                                        cost.decSpec( func->assertions.size() );
    325353                                }
    326354                        }
     
    329357                };
    330358
    331                 CandidateEnvMerger( 
    332                         const ast::TypeEnvironment & env, const ast::OpenVarSet & open, 
     359                CandidateEnvMerger(
     360                        const ast::TypeEnvironment & env, const ast::OpenVarSet & open,
    333361                        const ast::SymbolTable & syms )
    334362                : crnt(), envs{ env }, opens{ open }, symtab( syms ) {}
     
    357385
    358386        /// Limit to depth of recursion of assertion satisfaction
    359         static const int recursionLimit = 4;
     387        static const int recursionLimit = 8;
    360388        /// Maximum number of simultaneously-deferred assertions to attempt concurrent satisfaction of
    361389        static const int deferLimit = 10;
    362390} // anonymous namespace
    363391
    364 void satisfyAssertions( 
    365         CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 
     392void satisfyAssertions(
     393        CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
    366394        std::vector<std::string> & errors
    367395) {
     
    389417                        if ( it != thresholds.end() && it->second < sat.costs ) goto nextSat;
    390418
    391                         // make initial pass at matching assertions
    392                         for ( auto & assn : sat.need ) {
    393                                 // fail early if any assertion is not satisfiable
    394                                 if ( ! satisfyAssertion( assn, sat ) ) {
     419                        // should a limit be imposed? worst case here is O(n^2) but very unlikely to happen.
     420                        for (unsigned resetCount = 0; ; ++resetCount) {
     421                                ast::AssertionList next;
     422                                resetTyVarRenaming();
     423                                // make initial pass at matching assertions
     424                                for ( auto & assn : sat.need ) {
     425                                        // fail early if any assertion is not satisfiable
     426                                        if ( ! satisfyAssertion( assn, sat ) ) {
     427                                                next.emplace_back(assn);
     428                                                // goto nextSat;
     429                                        }
     430                                }
     431                                // success
     432                                if (next.empty()) break;
     433                                // fail if nothing resolves
     434                                else if (next.size() == sat.need.size()) {
    395435                                        Indenter tabs{ 3 };
    396436                                        std::ostringstream ss;
     
    398438                                        print( ss, *sat.cand, ++tabs );
    399439                                        ss << (tabs-1) << "Could not satisfy assertion:\n";
    400                                         ast::print( ss, assn.first, tabs );
     440                                        ast::print( ss, next[0].first, tabs );
    401441
    402442                                        errors.emplace_back( ss.str() );
    403443                                        goto nextSat;
    404444                                }
     445                                sat.need = std::move(next);
    405446                        }
    406447
     
    408449                                // either add successful match or push back next state
    409450                                if ( sat.newNeed.empty() ) {
    410                                         finalizeAssertions( 
     451                                        finalizeAssertions(
    411452                                                sat.cand, sat.inferred, thresholds, std::move( sat.costs ), out );
    412453                                } else {
     
    421462                                ss << (tabs-1) << "Too many non-unique satisfying assignments for assertions:\n";
    422463                                for ( const auto & d : sat.deferred ) {
    423                                         ast::print( ss, d.decl, tabs );
     464                                        ast::print( ss, d.expr, tabs );
    424465                                }
    425466
     
    430471                                std::vector< CandidateEnvMerger::OutType > compatible = filterCombos(
    431472                                        sat.deferred, CandidateEnvMerger{ sat.cand->env, sat.cand->open, sat.symtab } );
    432                                
     473
    433474                                // fail early if no mutually-compatible assertion satisfaction
    434475                                if ( compatible.empty() ) {
     
    439480                                        ss << (tabs-1) << "No mutually-compatible satisfaction for assertions:\n";
    440481                                        for ( const auto& d : sat.deferred ) {
    441                                                 ast::print( ss, d.decl, tabs );
     482                                                ast::print( ss, d.expr, tabs );
    442483                                        }
    443484
     
    453494                                        // set up next satisfaction state
    454495                                        CandidateRef nextCand = std::make_shared<Candidate>(
    455                                                 sat.cand->expr, std::move( compat.env ), std::move( compat.open ), 
     496                                                sat.cand->expr, std::move( compat.env ), std::move( compat.open ),
    456497                                                ast::AssertionSet{} /* need moved into satisfaction state */,
    457498                                                sat.cand->cost, sat.cand->cvtCost );
     
    459500                                        ast::AssertionSet nextNewNeed{ sat.newNeed };
    460501                                        InferCache nextInferred{ sat.inferred };
    461                                        
     502
    462503                                        CostVec nextCosts{ sat.costs };
    463504                                        nextCosts.back() += compat.cost;
    464                                                                
     505
    465506                                        ast::SymbolTable nextSymtab{ sat.symtab };
    466507
     
    471512                                                nextNewNeed.insert( match.need.begin(), match.need.end() );
    472513
    473                                                 bindAssertion( r.decl, r.info, nextCand, match, nextInferred );
     514                                                bindAssertion( r.expr, r.info, nextCand, match, nextInferred );
    474515                                        }
    475516
    476517                                        // either add successful match or push back next state
    477518                                        if ( nextNewNeed.empty() ) {
    478                                                 finalizeAssertions( 
     519                                                finalizeAssertions(
    479520                                                        nextCand, nextInferred, thresholds, std::move( nextCosts ), out );
    480521                                        } else {
    481                                                 nextSats.emplace_back( 
    482                                                         std::move( nextCand ), std::move( nextNewNeed ), 
    483                                                         std::move( nextInferred ), std::move( nextCosts ), 
     522                                                nextSats.emplace_back(
     523                                                        std::move( nextCand ), std::move( nextNewNeed ),
     524                                                        std::move( nextInferred ), std::move( nextCosts ),
    484525                                                        std::move( nextSymtab ) );
    485526                                        }
     
    493534                nextSats.clear();
    494535        }
    495        
     536
    496537        // exceeded recursion limit if reaches here
    497538        if ( out.empty() ) {
  • src/ResolvExpr/SatisfyAssertions.hpp

    r3c64c668 r58fe85a  
    2727namespace ResolvExpr {
    2828
    29 /// Recursively satisfies all assertions provided in a candidate; returns true if succeeds
    30 void satisfyAssertions(
    31         CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
     29/// Recursively satisfies all assertions provided in a candidate
     30/// returns true if it has been run (candidate has any assertions)
     31void satisfyAssertions(
     32        CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
    3233        std::vector<std::string> & errors );
    3334
  • src/ResolvExpr/SpecCost.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Tue Oct 02 15:50:00 2018
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jun 19 10:43:00 2019
    13 // Update Count     : 2
    14 //
    15 
     12// Last Modified On : Wed Jul  3 11:07:00 2019
     13// Update Count     : 3
     14//
     15
     16#include <cassert>
    1617#include <limits>
    1718#include <list>
     
    129130                        typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
    130131
     132                #warning Should use a standard maybe_accept
     133                void maybe_accept( ast::Type const * type ) {
     134                        if ( type ) {
     135                                auto node = type->accept( *visitor );
     136                                assert( node == nullptr || node == type );
     137                        }
     138                }
     139
    131140                // Update the minimum to the new lowest non-none value.
    132141                template<typename T>
     
    134143                        for ( const auto & node : list ) {
    135144                                count = -1;
    136                                 mapper( node )->accept( *visitor );
     145                                maybe_accept( mapper( node ) );
    137146                                if ( count != -1 && count < minimum ) minimum = count;
    138147                        }
     
    169178                void previsit( const ast::FunctionType * fty ) {
    170179                        int minCount = std::numeric_limits<int>::max();
    171                         updateMinimumPresent( minCount, fty->params, decl_type );
    172                         updateMinimumPresent( minCount, fty->returns, decl_type );
     180                        updateMinimumPresent( minCount, fty->params, type_deref );
     181                        updateMinimumPresent( minCount, fty->returns, type_deref );
    173182                        // Add another level to minCount if set.
    174183                        count = toNoneOrInc( minCount );
     
    208217        }
    209218        ast::Pass<SpecCounter> counter;
    210         type->accept( *counter.pass.visitor );
    211         return counter.pass.get_count();
     219        type->accept( counter );
     220        return counter.core.get_count();
    212221}
    213222
  • src/ResolvExpr/TypeEnvironment.cc

    r3c64c668 r58fe85a  
    2020#include <utility>                     // for pair, move
    2121
     22#include "CompilationState.h"          // for deterministic_output
    2223#include "Common/utility.h"            // for maybeClone
    2324#include "SynTree/Type.h"              // for Type, FunctionType, Type::Fora...
     
    106107
    107108        void EqvClass::print( std::ostream &os, Indenter indent ) const {
    108                 os << "( ";
    109                 std::copy( vars.begin(), vars.end(), std::ostream_iterator< std::string >( os, " " ) );
     109                os << "(";
     110                bool first = true;
     111                for(const auto & var : vars) {
     112                        if(first) first = false;
     113                        else os << " ";
     114                        if( deterministic_output && isUnboundType(var) ) os << "[unbound]";
     115                        else os << var;
     116                }
    110117                os << ")";
    111118                if ( type ) {
     
    235242                // check safely bindable
    236243                if ( r.type && occursIn( r.type, s.vars.begin(), s.vars.end(), *this ) ) return false;
    237                
     244
    238245                // merge classes in
    239246                r.vars.insert( s.vars.begin(), s.vars.end() );
  • src/ResolvExpr/TypeEnvironment.h

    r3c64c668 r58fe85a  
    149149                iterator end() const { return env.end(); }
    150150
     151                auto size() const { return env.size(); }
     152
    151153          private:
    152154                ClassList env;
  • src/ResolvExpr/Unify.cc

    r3c64c668 r58fe85a  
    2525#include <vector>
    2626
     27#include "AST/Copy.hpp"
    2728#include "AST/Decl.hpp"
    2829#include "AST/Node.hpp"
    2930#include "AST/Pass.hpp"
     31#include "AST/Print.hpp"
    3032#include "AST/Type.hpp"
    3133#include "AST/TypeEnvironment.hpp"
     
    135137                findOpenVars( newSecond, open, closed, need, have, FirstOpen );
    136138
    137                 return unifyExact(
    138                         newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     139                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
    139140        }
    140141
     
    148149                newFirst->get_qualifiers() = Type::Qualifiers();
    149150                newSecond->get_qualifiers() = Type::Qualifiers();
    150 ///   std::cerr << "first is ";
    151 ///   first->print( std::cerr );
    152 ///   std::cerr << std::endl << "second is ";
    153 ///   second->print( std::cerr );
    154 ///   std::cerr << std::endl << "newFirst is ";
    155 ///   newFirst->print( std::cerr );
    156 ///   std::cerr << std::endl << "newSecond is ";
    157 ///   newSecond->print( std::cerr );
    158 ///   std::cerr << std::endl;
     151
    159152                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    160153                delete newFirst;
     
    170163                ast::AssertionSet need, have;
    171164
    172                 ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
    173                 env.apply( newFirst );
    174                 env.apply( newSecond );
    175                 reset_qualifiers( newFirst );
    176                 reset_qualifiers( newSecond );
     165                ast::Type * newFirst  = shallowCopy( first  );
     166                ast::Type * newSecond = shallowCopy( second );
     167                newFirst ->qualifiers = {};
     168                newSecond->qualifiers = {};
     169                ast::ptr< ast::Type > t1_(newFirst );
     170                ast::ptr< ast::Type > t2_(newSecond);
     171
     172                ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
     173                ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
    177174
    178175                return unifyExact(
    179                         newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     176                        subFirst,
     177                        subSecond,
     178                        newEnv, need, have, open, noWiden(), symtab );
    180179        }
    181180
     
    326325
    327326        void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
    328 ///   std::cerr << "assertion set is" << std::endl;
    329 ///   printAssertionSet( assertions, std::cerr, 8 );
    330 ///   std::cerr << "looking for ";
    331 ///   assert->print( std::cerr );
    332 ///   std::cerr << std::endl;
    333327                AssertionSet::iterator i = assertions.find( assert );
    334328                if ( i != assertions.end() ) {
    335 ///     std::cerr << "found it!" << std::endl;
    336329                        i->second.isUsed = true;
    337330                } // if
     
    402395
    403396        template< typename Iterator1, typename Iterator2 >
    404         bool unifyDeclList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     397        bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    405398                auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };
    406399                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
     
    496489                                        || flatOther->isTtype()
    497490                        ) {
    498                                 if ( unifyDeclList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    499                                         if ( unifyDeclList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     491                                if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     492                                        if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    500493
    501494                                                // the original types must be used in mark assertions, since pointer comparisons are used
     
    709702                const ast::SymbolTable & symtab;
    710703        public:
     704                static size_t traceId;
    711705                bool result;
    712706
     
    773767                /// If this isn't done when satifying ttype assertions, then argument lists can have
    774768                /// different size and structure when they should be compatible.
    775                 struct TtypeExpander_new : public ast::WithShortCircuiting {
     769                struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor {
    776770                        ast::TypeEnvironment & tenv;
    777771
     
    779773
    780774                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
    781                                 if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name ) ) {
     775                                if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
    782776                                        // expand ttype parameter into its actual type
    783777                                        if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
     
    790784
    791785                /// returns flattened version of `src`
    792                 static std::vector< ast::ptr< ast::DeclWithType > > flattenList(
    793                         const std::vector< ast::ptr< ast::DeclWithType > > & src, ast::TypeEnvironment & env
     786                static std::vector< ast::ptr< ast::Type > > flattenList(
     787                        const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
    794788                ) {
    795                         std::vector< ast::ptr< ast::DeclWithType > > dst;
     789                        std::vector< ast::ptr< ast::Type > > dst;
    796790                        dst.reserve( src.size() );
    797                         for ( const ast::DeclWithType * d : src ) {
     791                        for ( const auto & d : src ) {
    798792                                ast::Pass<TtypeExpander_new> expander{ env };
    799                                 d = d->accept( expander );
    800                                 auto types = flatten( d->get_type() );
     793                                // TtypeExpander pass is impure (may mutate nodes in place)
     794                                // need to make nodes shared to prevent accidental mutation
     795                                ast::ptr<ast::Type> dc = d->accept(expander);
     796                                auto types = flatten( dc );
    801797                                for ( ast::ptr< ast::Type > & t : types ) {
    802798                                        // outermost const, volatile, _Atomic qualifiers in parameters should not play
     
    807803                                        // requirements than a non-mutex function
    808804                                        remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
    809                                         dst.emplace_back( new ast::ObjectDecl{ d->location, "", t } );
     805                                        dst.emplace_back( t );
    810806                                }
    811807                        }
     
    815811                /// Creates a tuple type based on a list of DeclWithType
    816812                template< typename Iter >
    817                 static ast::ptr< ast::Type > tupleFromDecls( Iter crnt, Iter end ) {
     813                static const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
    818814                        std::vector< ast::ptr< ast::Type > > types;
    819815                        while ( crnt != end ) {
    820816                                // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
    821817                                // that this results in a flat tuple
    822                                 flatten( (*crnt)->get_type(), types );
     818                                flatten( *crnt, types );
    823819
    824820                                ++crnt;
    825821                        }
    826822
    827                         return { new ast::TupleType{ std::move(types) } };
     823                        return new ast::TupleType{ std::move(types) };
    828824                }
    829825
    830826                template< typename Iter >
    831                 static bool unifyDeclList(
     827                static bool unifyTypeList(
    832828                        Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
    833829                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     
    835831                ) {
    836832                        while ( crnt1 != end1 && crnt2 != end2 ) {
    837                                 const ast::Type * t1 = (*crnt1)->get_type();
    838                                 const ast::Type * t2 = (*crnt2)->get_type();
     833                                const ast::Type * t1 = *crnt1;
     834                                const ast::Type * t2 = *crnt2;
    839835                                bool isTuple1 = Tuples::isTtype( t1 );
    840836                                bool isTuple2 = Tuples::isTtype( t2 );
     
    844840                                        // combine remainder of list2, then unify
    845841                                        return unifyExact(
    846                                                 t1, tupleFromDecls( crnt2, end2 ), env, need, have, open,
     842                                                t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
    847843                                                noWiden(), symtab );
    848844                                } else if ( ! isTuple1 && isTuple2 ) {
    849845                                        // combine remainder of list1, then unify
    850846                                        return unifyExact(
    851                                                 tupleFromDecls( crnt1, end1 ), t2, env, need, have, open,
     847                                                tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
    852848                                                noWiden(), symtab );
    853849                                }
     
    864860                        if ( crnt1 != end1 ) {
    865861                                // try unifying empty tuple with ttype
    866                                 const ast::Type * t1 = (*crnt1)->get_type();
     862                                const ast::Type * t1 = *crnt1;
    867863                                if ( ! Tuples::isTtype( t1 ) ) return false;
    868864                                return unifyExact(
    869                                         t1, tupleFromDecls( crnt2, end2 ), env, need, have, open,
     865                                        t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
    870866                                        noWiden(), symtab );
    871867                        } else if ( crnt2 != end2 ) {
    872868                                // try unifying empty tuple with ttype
    873                                 const ast::Type * t2 = (*crnt2)->get_type();
     869                                const ast::Type * t2 = *crnt2;
    874870                                if ( ! Tuples::isTtype( t2 ) ) return false;
    875871                                return unifyExact(
    876                                         tupleFromDecls( crnt1, end1 ), t2, env, need, have, open,
     872                                        tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
    877873                                        noWiden(), symtab );
    878874                        }
     
    881877                }
    882878
    883                 static bool unifyDeclList(
    884                         const std::vector< ast::ptr< ast::DeclWithType > > & list1,
    885                         const std::vector< ast::ptr< ast::DeclWithType > > & list2,
     879                static bool unifyTypeList(
     880                        const std::vector< ast::ptr< ast::Type > > & list1,
     881                        const std::vector< ast::ptr< ast::Type > > & list2,
    886882                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    887883                        const ast::OpenVarSet & open, const ast::SymbolTable & symtab
    888884                ) {
    889                         return unifyDeclList(
     885                        return unifyTypeList(
    890886                                list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open,
    891887                                symtab );
    892888                }
    893889
    894                 static void markAssertionSet( ast::AssertionSet & assns, const ast::DeclWithType * assn ) {
     890                static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
    895891                        auto i = assns.find( assn );
    896892                        if ( i != assns.end() ) {
     
    902898                static void markAssertions(
    903899                        ast::AssertionSet & assn1, ast::AssertionSet & assn2,
    904                         const ast::ParameterizedType * type
     900                        const ast::FunctionType * type
    905901                ) {
    906                         for ( const auto & tyvar : type->forall ) {
    907                                 for ( const ast::DeclWithType * assert : tyvar->assertions ) {
    908                                         markAssertionSet( assn1, assert );
    909                                         markAssertionSet( assn2, assert );
    910                                 }
     902                        for ( auto & assert : type->assertions ) {
     903                                markAssertionSet( assn1, assert );
     904                                markAssertionSet( assn2, assert );
    911905                        }
    912906                }
     
    932926                        ) return;
    933927
    934                         if ( ! unifyDeclList( params, params2, tenv, need, have, open, symtab ) ) return;
    935                         if ( ! unifyDeclList(
     928                        if ( ! unifyTypeList( params, params2, tenv, need, have, open, symtab ) ) return;
     929                        if ( ! unifyTypeList(
    936930                                func->returns, func2->returns, tenv, need, have, open, symtab ) ) return;
    937931
     
    943937
    944938        private:
    945                 template< typename RefType >
    946                 const RefType * handleRefType( const RefType * inst, const ast::Type * other ) {
     939                // Returns: other, cast as XInstType
     940                // Assigns this->result: whether types are compatible (up to generic parameters)
     941                template< typename XInstType >
     942                const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
    947943                        // check that the other type is compatible and named the same
    948                         auto otherInst = dynamic_cast< const RefType * >( other );
    949                         result = otherInst && inst->name == otherInst->name;
     944                        auto otherInst = dynamic_cast< const XInstType * >( other );
     945                        this->result = otherInst && inst->name == otherInst->name;
    950946                        return otherInst;
    951947                }
     
    968964                }
    969965
    970                 template< typename RefType >
    971                 void handleGenericRefType( const RefType * inst, const ast::Type * other ) {
     966                template< typename XInstType >
     967                void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
    972968                        // check that other type is compatible and named the same
    973                         const RefType * inst2 = handleRefType( inst, other );
    974                         if ( ! inst2 ) return;
     969                        const XInstType * otherInst = handleRefType( inst, other );
     970                        if ( ! this->result ) return;
    975971
    976972                        // check that parameters of types unify, if any
    977973                        const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
    978                         const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;
     974                        const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
    979975
    980976                        auto it = params.begin();
     
    10321028
    10331029                void postvisit( const ast::TypeInstType * typeInst ) {
    1034                         assert( open.find( typeInst->name ) == open.end() );
     1030                        assert( open.find( *typeInst ) == open.end() );
    10351031                        handleRefType( typeInst, type2 );
    10361032                }
     
    10381034        private:
    10391035                /// Creates a tuple type based on a list of Type
    1040                 static ast::ptr< ast::Type > tupleFromTypes(
     1036                static const ast::Type * tupleFromTypes(
    10411037                        const std::vector< ast::ptr< ast::Type > > & tys
    10421038                ) {
     
    11141110
    11151111                        ast::Pass<TtypeExpander_new> expander{ tenv };
     1112
    11161113                        const ast::Type * flat = tuple->accept( expander );
    11171114                        const ast::Type * flat2 = tuple2->accept( expander );
     
    11401137        };
    11411138
     1139        // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new");
    11421140        bool unify(
    11431141                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     
    11711169                auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
    11721170                ast::OpenVarSet::const_iterator
    1173                         entry1 = var1 ? open.find( var1->name ) : open.end(),
    1174                         entry2 = var2 ? open.find( var2->name ) : open.end();
     1171                        entry1 = var1 ? open.find( *var1 ) : open.end(),
     1172                        entry2 = var2 ? open.find( *var2 ) : open.end();
    11751173                bool isopen1 = entry1 != open.end();
    11761174                bool isopen2 = entry2 != open.end();
     
    11881186                        ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab };
    11891187                        type1->accept( comparator );
    1190                         return comparator.pass.result;
     1188                        return comparator.core.result;
    11911189                }
    11921190        }
     
    12021200                // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
    12031201                // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
    1204                 ast::ptr<ast::Type> t1{ type1 }, t2{ type2 };
    1205                 reset_qualifiers( t1 );
    1206                 reset_qualifiers( t2 );
     1202                ast::Type * t1 = shallowCopy(type1.get());
     1203                ast::Type * t2 = shallowCopy(type2.get());
     1204                t1->qualifiers = {};
     1205                t2->qualifiers = {};
     1206                ast::ptr< ast::Type > t1_(t1);
     1207                ast::ptr< ast::Type > t2_(t2);
    12071208
    12081209                if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) {
    1209                         t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
    1210 
    12111210                        // if exact unification on unqualified types, try to merge qualifiers
    12121211                        if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
    1213                                 common = type1;
    1214                                 reset_qualifiers( common, q1 | q2 );
     1212                                t1->qualifiers = q1 | q2;
     1213                                common = t1;
    12151214                                return true;
    12161215                        } else {
     
    12191218
    12201219                } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) {
    1221                         t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
    1222 
    12231220                        // no exact unification, but common type
    1224                         reset_qualifiers( common, q1 | q2 );
     1221                        auto c = shallowCopy(common.get());
     1222                        c->qualifiers = q1 | q2;
     1223                        common = c;
    12251224                        return true;
    12261225                } else {
     
    12311230        ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
    12321231                if ( func->returns.empty() ) return new ast::VoidType{};
    1233                 if ( func->returns.size() == 1 ) return func->returns[0]->get_type();
     1232                if ( func->returns.size() == 1 ) return func->returns[0];
    12341233
    12351234                std::vector<ast::ptr<ast::Type>> tys;
    1236                 for ( const ast::DeclWithType * decl : func->returns ) {
    1237                         tys.emplace_back( decl->get_type() );
     1235                for ( const auto & decl : func->returns ) {
     1236                        tys.emplace_back( decl );
    12381237                }
    12391238                return new ast::TupleType{ std::move(tys) };
  • src/ResolvExpr/module.mk

    r3c64c668 r58fe85a  
    1919      ResolvExpr/Alternative.cc \
    2020      ResolvExpr/AlternativeFinder.cc \
     21      ResolvExpr/AlternativeFinder.h \
     22      ResolvExpr/Alternative.h \
    2123      ResolvExpr/Candidate.cpp \
    2224      ResolvExpr/CandidateFinder.cpp \
     25      ResolvExpr/CandidateFinder.hpp \
     26      ResolvExpr/Candidate.hpp \
    2327      ResolvExpr/CastCost.cc \
    2428      ResolvExpr/CommonType.cc \
    2529      ResolvExpr/ConversionCost.cc \
     30      ResolvExpr/ConversionCost.h \
     31      ResolvExpr/Cost.h \
    2632      ResolvExpr/CurrentObject.cc \
     33      ResolvExpr/CurrentObject.h \
    2734      ResolvExpr/ExplodedActual.cc \
     35      ResolvExpr/ExplodedActual.h \
    2836      ResolvExpr/ExplodedArg.cpp \
     37      ResolvExpr/ExplodedArg.hpp \
    2938      ResolvExpr/FindOpenVars.cc \
     39      ResolvExpr/FindOpenVars.h \
    3040      ResolvExpr/Occurs.cc \
    3141      ResolvExpr/PolyCost.cc \
     
    3343      ResolvExpr/PtrsCastable.cc \
    3444      ResolvExpr/RenameVars.cc \
     45      ResolvExpr/RenameVars.h \
    3546      ResolvExpr/ResolveAssertions.cc \
     47      ResolvExpr/ResolveAssertions.h \
    3648      ResolvExpr/Resolver.cc \
     49      ResolvExpr/Resolver.h \
    3750      ResolvExpr/ResolveTypeof.cc \
     51      ResolvExpr/ResolveTypeof.h \
     52      ResolvExpr/ResolvMode.h \
    3853      ResolvExpr/SatisfyAssertions.cpp \
     54      ResolvExpr/SatisfyAssertions.hpp \
    3955      ResolvExpr/SpecCost.cc \
    4056      ResolvExpr/TypeEnvironment.cc \
    41       ResolvExpr/Unify.cc
     57      ResolvExpr/TypeEnvironment.h \
     58      ResolvExpr/typeops.h \
     59      ResolvExpr/Unify.cc \
     60      ResolvExpr/Unify.h \
     61      ResolvExpr/WidenMode.h
    4262
    43 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc
     63
     64SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc ResolvExpr/AlternativePrinter.h
    4465SRCDEMANGLE += $(SRC_RESOLVEXPR)
  • src/ResolvExpr/typeops.h

    r3c64c668 r58fe85a  
    1010// Created On       : Sun May 17 07:28:22 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Aug  8 16:36:00 2019
    13 // Update Count     : 5
     12// Last Modified On : Tue Oct  1 09:45:00 2019
     13// Update Count     : 6
    1414//
    1515
     
    8383                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    8484        Cost castCost(
    85                 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    86                 const ast::TypeEnvironment & env );
     85                const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     86                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    8787
    8888        // in ConversionCost.cc
     
    9090                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    9191        Cost conversionCost(
    92                 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    93                 const ast::TypeEnvironment & env );
     92                const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     93                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    9494
    9595        // in AlternativeFinder.cc
  • src/SymTab/Autogen.cc

    r3c64c668 r58fe85a  
    3838#include "SynTree/Type.h"          // for FunctionType, Type, TypeInstType
    3939#include "SynTree/Visitor.h"       // for maybeAccept, Visitor, acceptAll
     40#include "CompilationState.h"
    4041
    4142class Attribute;
     
    233234        }
    234235
     236        // shallow copy the pointer list for return
     237        std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) {
     238                if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) {
     239                        return structInst->base->params;
     240                }
     241                if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) {
     242                        return unionInst->base->params;
     243                }
     244                return {};
     245        }
     246
    235247        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    236248        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    244256                ftype->parameters.push_back( dstParam );
    245257                return ftype;
     258        }
     259
     260        ///
     261        ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) {
     262                std::vector<ast::ptr<ast::TypeDecl>> typeParams;
     263                if (maybePolymorphic) typeParams = getGenericParams(paramType);
     264                auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall);
     265                return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc));
    246266        }
    247267
     
    327347        void FuncGenerator::resolve( FunctionDecl * dcl ) {
    328348                try {
    329                         ResolvExpr::resolveDecl( dcl, indexer );
     349                        if (!useNewAST) // attempt to delay resolver call
     350                                ResolvExpr::resolveDecl( dcl, indexer );
    330351                        if ( functionNesting == 0 ) {
    331352                                // forward declare if top-level struct, so that
     
    339360                } catch ( SemanticErrorException & ) {
    340361                        // okay if decl does not resolve - that means the function should not be generated
    341                         delete dcl;
     362                        // delete dcl;
     363                        delete dcl->statements;
     364                        dcl->statements = nullptr;
     365                        dcl->isDeleted = true;
     366                        definitions.push_back( dcl );
     367                        indexer.addId( dcl );
    342368                }
    343369        }
  • src/SymTab/Autogen.h

    r3c64c668 r58fe85a  
    2121
    2222#include "AST/Decl.hpp"
     23#include "AST/Eval.hpp"
    2324#include "AST/Expr.hpp"
    2425#include "AST/Init.hpp"
     
    5455        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
    5556        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
     57
     58        ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);
    5659
    5760        /// generate the type of a copy constructor for paramType.
     
    164167                fExpr->args.emplace_back( dstParam );
    165168
    166                 const ast::Stmt * listInit = srcParam.buildListInit( fExpr );
     169                ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
    167170
    168171                // fetch next set of arguments
     
    265268                }
    266269
    267                 ast::ptr< ast::Expr > begin, end, cmp, update;
     270                ast::ptr< ast::Expr > begin, end;
     271                std::string cmp, update;
    268272
    269273                if ( forward ) {
     
    271275                        begin = ast::ConstantExpr::from_int( loc, 0 );
    272276                        end = array->dimension;
    273                         cmp = new ast::NameExpr{ loc, "?<?" };
    274                         update = new ast::NameExpr{ loc, "++?" };
     277                        cmp = "?<?";
     278                        update = "++?";
    275279                } else {
    276280                        // generate: for ( int i = N-1; i >= 0; --i )
    277                         begin = new ast::UntypedExpr{
    278                                 loc, new ast::NameExpr{ loc, "?-?" },
    279                                 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } };
     281                        begin = ast::call(
     282                                loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
    280283                        end = ast::ConstantExpr::from_int( loc, 0 );
    281                         cmp = new ast::NameExpr{ loc, "?>=?" };
    282                         update = new ast::NameExpr{ loc, "--?" };
     284                        cmp = "?>=?";
     285                        update = "--?";
    283286                }
    284287
     
    286289                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
    287290                        new ast::SingleInit{ loc, begin } };
    288                
    289                 ast::ptr< ast::Expr > cond = new ast::UntypedExpr{
    290                         loc, cmp, { new ast::VariableExpr{ loc, index }, end } };
    291                
    292                 ast::ptr< ast::Expr > inc = new ast::UntypedExpr{
    293                         loc, update, { new ast::VariableExpr{ loc, index } } };
    294                
    295                 ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{
    296                         loc, new ast::NameExpr{ loc, "?[?]" },
    297                         { dstParam, new ast::VariableExpr{ loc, index } } };
     291                ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
     292               
     293                ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
     294               
     295                ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
     296               
     297                ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
    298298               
    299299                // srcParam must keep track of the array indices to build the source parameter and/or
    300300                // array list initializer
    301                 srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );
     301                srcParam.addArrayIndex( indexVar, array->dimension );
    302302
    303303                // for stmt's body, eventually containing call
     
    385385                if ( isUnnamedBitfield( obj ) ) return {};
    386386
    387                 ast::ptr< ast::Type > addCast = nullptr;
     387                ast::ptr< ast::Type > addCast;
    388388                if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
    389389                        assert( dstParam->result );
  • src/SymTab/FixFunction.cc

    r3c64c668 r58fe85a  
    106106                bool isVoid = false;
    107107
    108                 void premutate( const ast::FunctionDecl * ) { visit_children = false; }
     108                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    109109
    110                 const ast::DeclWithType * postmutate( const ast::FunctionDecl * func ) {
     110                const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
    111111                        return new ast::ObjectDecl{
    112112                                func->location, func->name, new ast::PointerType{ func->type }, nullptr,
     
    114114                }
    115115
    116                 void premutate( const ast::ArrayType * ) { visit_children = false; }
     116                void previsit( const ast::ArrayType * ) { visit_children = false; }
    117117
    118                 const ast::Type * postmutate( const ast::ArrayType * array ) {
     118                const ast::Type * postvisit( const ast::ArrayType * array ) {
    119119                        return new ast::PointerType{
    120120                                array->base, array->dimension, array->isVarLen, array->isStatic,
     
    122122                }
    123123
    124                 void premutate( const ast::VoidType * ) { isVoid = true; }
     124                void previsit( const ast::VoidType * ) { isVoid = true; }
    125125
    126                 void premutate( const ast::BasicType * ) { visit_children = false; }
    127                 void premutate( const ast::PointerType * ) { visit_children = false; }
    128                 void premutate( const ast::StructInstType * ) { visit_children = false; }
    129                 void premutate( const ast::UnionInstType * ) { visit_children = false; }
    130                 void premutate( const ast::EnumInstType * ) { visit_children = false; }
    131                 void premutate( const ast::TraitInstType * ) { visit_children = false; }
    132                 void premutate( const ast::TypeInstType * ) { visit_children = false; }
    133                 void premutate( const ast::TupleType * ) { visit_children = false; }
    134                 void premutate( const ast::VarArgsType * ) { visit_children = false; }
    135                 void premutate( const ast::ZeroType * ) { visit_children = false; }
    136                 void premutate( const ast::OneType * ) { visit_children = false; }
     126                void previsit( const ast::BasicType * ) { visit_children = false; }
     127                void previsit( const ast::PointerType * ) { visit_children = false; }
     128                void previsit( const ast::StructInstType * ) { visit_children = false; }
     129                void previsit( const ast::UnionInstType * ) { visit_children = false; }
     130                void previsit( const ast::EnumInstType * ) { visit_children = false; }
     131                void previsit( const ast::TraitInstType * ) { visit_children = false; }
     132                void previsit( const ast::TypeInstType * ) { visit_children = false; }
     133                void previsit( const ast::TupleType * ) { visit_children = false; }
     134                void previsit( const ast::VarArgsType * ) { visit_children = false; }
     135                void previsit( const ast::ZeroType * ) { visit_children = false; }
     136                void previsit( const ast::OneType * ) { visit_children = false; }
    137137        };
    138138} // anonymous namespace
     
    141141        ast::Pass< FixFunction_new > fixer;
    142142        dwt = dwt->accept( fixer );
    143         isVoid |= fixer.pass.isVoid;
     143        isVoid |= fixer.core.isVoid;
    144144        return dwt;
    145145}
  • src/SymTab/Mangler.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Sun May 17 21:40:29 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 13:55:12 2020
    13 // Update Count     : 33
     12// Last Modified On : Wed Nov 18 12:01:38 2020
     13// Update Count     : 64
    1414//
    1515#include "Mangler.h"
     
    6565                                void postvisit( const QualifiedType * qualType );
    6666
    67                                 std::string get_mangleName() { return mangleName.str(); }
     67                                std::string get_mangleName() { return mangleName; }
    6868                          private:
    69                                 std::ostringstream mangleName;  ///< Mangled name being constructed
     69                                std::string mangleName;         ///< Mangled name being constructed
    7070                                typedef std::map< std::string, std::pair< int, int > > VarMapType;
    7171                                VarMapType varNums;             ///< Map of type variables to indices
     
    127127                                        isTopLevel = false;
    128128                                } // if
    129                                 mangleName << Encoding::manglePrefix;
     129                                mangleName += Encoding::manglePrefix;
    130130                                const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( declaration->get_name() );
    131131                                if ( opInfo ) {
    132                                         mangleName << opInfo->outputName.size() << opInfo->outputName;
     132                                        mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
    133133                                } else {
    134                                         mangleName << declaration->name.size() << declaration->name;
     134                                        mangleName += std::to_string( declaration->name.size() ) + declaration->name;
    135135                                } // if
    136136                                maybeAccept( declaration->get_type(), *visitor );
     
    139139                                        // so they need a different name mangling
    140140                                        if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
    141                                                 mangleName << Encoding::autogen;
     141                                                mangleName += Encoding::autogen;
    142142                                        } else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
    143                                                 mangleName << Encoding::intrinsic;
     143                                                mangleName += Encoding::intrinsic;
    144144                                        } else {
    145145                                                // if we add another kind of overridable function, this has to change
     
    160160                        void Mangler_old::postvisit( const VoidType * voidType ) {
    161161                                printQualifiers( voidType );
    162                                 mangleName << Encoding::void_t;
     162                                mangleName += Encoding::void_t;
    163163                        }
    164164
     
    166166                                printQualifiers( basicType );
    167167                                assertf( basicType->kind < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
    168                                 mangleName << Encoding::basicTypes[ basicType->kind ];
     168                                mangleName += Encoding::basicTypes[ basicType->kind ];
    169169                        }
    170170
     
    172172                                printQualifiers( pointerType );
    173173                                // 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;
     174                                if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName += Encoding::pointer;
    175175                                maybeAccept( pointerType->base, *visitor );
    176176                        }
     
    179179                                // TODO: encode dimension
    180180                                printQualifiers( arrayType );
    181                                 mangleName << Encoding::array << "0";
     181                                mangleName += Encoding::array + "0";
    182182                                maybeAccept( arrayType->base, *visitor );
    183183                        }
     
    204204                        void Mangler_old::postvisit( const FunctionType * functionType ) {
    205205                                printQualifiers( functionType );
    206                                 mangleName << Encoding::function;
     206                                mangleName += Encoding::function;
    207207                                // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
    208208                                // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
     
    211211                                inFunctionType = true;
    212212                                std::list< Type* > returnTypes = getTypes( functionType->returnVals );
    213                                 if (returnTypes.empty()) mangleName << Encoding::void_t;
     213                                if (returnTypes.empty()) mangleName += Encoding::void_t;
    214214                                else acceptAll( returnTypes, *visitor );
    215                                 mangleName << "_";
     215                                mangleName += "_";
    216216                                std::list< Type* > paramTypes = getTypes( functionType->parameters );
    217217                                acceptAll( paramTypes, *visitor );
    218                                 mangleName << "_";
     218                                mangleName += "_";
    219219                        }
    220220
     
    222222                                printQualifiers( refType );
    223223
    224                                 mangleName << prefix << refType->name.length() << refType->name;
     224                                mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
    225225
    226226                                if ( mangleGenericParams ) {
    227227                                        const std::list< Expression* > & params = refType->parameters;
    228228                                        if ( ! params.empty() ) {
    229                                                 mangleName << "_";
     229                                                mangleName += "_";
    230230                                                for ( const Expression * param : params ) {
    231231                                                        const TypeExpr * paramType = dynamic_cast< const TypeExpr * >( param );
     
    233233                                                        maybeAccept( paramType->type, *visitor );
    234234                                                }
    235                                                 mangleName << "_";
     235                                                mangleName += "_";
    236236                                        }
    237237                                }
     
    262262                                        // are first found and prefixing with the appropriate encoding for the type class.
    263263                                        assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    264                                         mangleName << Encoding::typeVariables[varNum->second.second] << varNum->second.first;
     264                                        mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    265265                                } // if
    266266                        }
     
    268268                        void Mangler_old::postvisit( const TraitInstType * inst ) {
    269269                                printQualifiers( inst );
    270                                 mangleName << inst->name.size() << inst->name;
     270                                mangleName += std::to_string( inst->name.size() ) + inst->name;
    271271                        }
    272272
    273273                        void Mangler_old::postvisit( const TupleType * tupleType ) {
    274274                                printQualifiers( tupleType );
    275                                 mangleName << Encoding::tuple << tupleType->types.size();
     275                                mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
    276276                                acceptAll( tupleType->types, *visitor );
    277277                        }
     
    280280                                printQualifiers( varArgsType );
    281281                                static const std::string vargs = "__builtin_va_list";
    282                                 mangleName << Encoding::type << vargs.size() << vargs;
     282                                mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
    283283                        }
    284284
    285285                        void Mangler_old::postvisit( const ZeroType * ) {
    286                                 mangleName << Encoding::zero;
     286                                mangleName += Encoding::zero;
    287287                        }
    288288
    289289                        void Mangler_old::postvisit( const OneType * ) {
    290                                 mangleName << Encoding::one;
     290                                mangleName += Encoding::one;
    291291                        }
    292292
     
    296296                                        // N marks the start of a qualified type
    297297                                        inQualifiedType = true;
    298                                         mangleName << Encoding::qualifiedTypeStart;
     298                                        mangleName += Encoding::qualifiedTypeStart;
    299299                                }
    300300                                maybeAccept( qualType->parent, *visitor );
     
    303303                                        // E marks the end of a qualified type
    304304                                        inQualifiedType = false;
    305                                         mangleName << Encoding::qualifiedTypeEnd;
     305                                        mangleName += Encoding::qualifiedTypeEnd;
    306306                                }
    307307                        }
     
    315315                                assertf(false, "Mangler_old should not visit typedecl: %s", toCString(decl));
    316316                                assertf( decl->kind < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    317                                 mangleName << Encoding::typeVariables[ decl->kind ] << ( decl->name.length() ) << decl->name;
     317                                mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
    318318                        }
    319319
     
    330330                                        std::list< std::string > assertionNames;
    331331                                        int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    332                                         mangleName << Encoding::forall;
     332                                        mangleName += Encoding::forall;
    333333                                        for ( const TypeDecl * i : type->forall ) {
    334334                                                switch ( i->kind ) {
     
    354354                                                } // for
    355355                                        } // for
    356                                         mangleName << dcount << "_" << fcount << "_" << vcount << "_" << acount << "_";
    357                                         std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    358                                         mangleName << "_";
     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 += "_";
    359360                                } // if
    360361                                if ( ! inFunctionType ) {
    361362                                        // these qualifiers do not distinguish the outermost type of a function parameter
    362363                                        if ( type->get_const() ) {
    363                                                 mangleName << Encoding::qualifiers.at(Type::Const);
     364                                                mangleName += Encoding::qualifiers.at(Type::Const);
    364365                                        } // if
    365366                                        if ( type->get_volatile() ) {
    366                                                 mangleName << Encoding::qualifiers.at(Type::Volatile);
     367                                                mangleName += Encoding::qualifiers.at(Type::Volatile);
    367368                                        } // if
    368369                                        // Removed due to restrict not affecting function compatibility in GCC
    369370                                        // if ( type->get_isRestrict() ) {
    370                                         //      mangleName << "E";
     371                                        //      mangleName += "E";
    371372                                        // } // if
    372373                                        if ( type->get_atomic() ) {
    373                                                 mangleName << Encoding::qualifiers.at(Type::Atomic);
     374                                                mangleName += Encoding::qualifiers.at(Type::Atomic);
    374375                                        } // if
    375376                                }
    376377                                if ( type->get_mutex() ) {
    377                                         mangleName << Encoding::qualifiers.at(Type::Mutex);
     378                                        mangleName += Encoding::qualifiers.at(Type::Mutex);
    378379                                } // if
    379380                                if ( inFunctionType ) {
     
    383384                                }
    384385                        }
    385                 }       // namespace
     386                } // namespace
    386387        } // namespace Mangler
    387388} // namespace SymTab
     
    417418                        void postvisit( const ast::QualifiedType * qualType );
    418419
    419                         std::string get_mangleName() { return mangleName.str(); }
     420                        std::string get_mangleName() { return mangleName; }
    420421                  private:
    421                         std::ostringstream mangleName;  ///< Mangled name being constructed
     422                        std::string mangleName;         ///< Mangled name being constructed
    422423                        typedef std::map< std::string, std::pair< int, int > > VarMapType;
    423424                        VarMapType varNums;             ///< Map of type variables to indices
     
    437438                  private:
    438439                        void mangleDecl( const ast::DeclWithType *declaration );
    439                         void mangleRef( const ast::ReferenceToType *refType, std::string prefix );
     440                        void mangleRef( const ast::BaseInstType *refType, std::string prefix );
    440441
    441442                        void printQualifiers( const ast::Type *type );
     
    447448                ast::Pass<Mangler_new> mangler( mode );
    448449                maybeAccept( decl, mangler );
    449                 return mangler.pass.get_mangleName();
     450                return mangler.core.get_mangleName();
    450451        }
    451452
     
    470471                                isTopLevel = false;
    471472                        } // if
    472                         mangleName << Encoding::manglePrefix;
     473                        mangleName += Encoding::manglePrefix;
    473474                        const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name );
    474475                        if ( opInfo ) {
    475                                 mangleName << opInfo->outputName.size() << opInfo->outputName;
     476                                mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
    476477                        } else {
    477                                 mangleName << decl->name.size() << decl->name;
     478                                mangleName += std::to_string( decl->name.size() ) + decl->name;
    478479                        } // if
    479480                        maybeAccept( decl->get_type(), *visitor );
     
    482483                                // so they need a different name mangling
    483484                                if ( decl->linkage == ast::Linkage::AutoGen ) {
    484                                         mangleName << Encoding::autogen;
     485                                        mangleName += Encoding::autogen;
    485486                                } else if ( decl->linkage == ast::Linkage::Intrinsic ) {
    486                                         mangleName << Encoding::intrinsic;
     487                                        mangleName += Encoding::intrinsic;
    487488                                } else {
    488489                                        // if we add another kind of overridable function, this has to change
     
    503504                void Mangler_new::postvisit( const ast::VoidType * voidType ) {
    504505                        printQualifiers( voidType );
    505                         mangleName << Encoding::void_t;
     506                        mangleName += Encoding::void_t;
    506507                }
    507508
     
    509510                        printQualifiers( basicType );
    510511                        assertf( basicType->kind < ast::BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
    511                         mangleName << Encoding::basicTypes[ basicType->kind ];
     512                        mangleName += Encoding::basicTypes[ basicType->kind ];
    512513                }
    513514
     
    515516                        printQualifiers( pointerType );
    516517                        // mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
    517                         if ( ! pointerType->base.as<ast::FunctionType>() ) mangleName << Encoding::pointer;
     518                        if ( ! pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer;
    518519                        maybe_accept( pointerType->base.get(), *visitor );
    519520                }
     
    522523                        // TODO: encode dimension
    523524                        printQualifiers( arrayType );
    524                         mangleName << Encoding::array << "0";
     525                        mangleName += Encoding::array + "0";
    525526                        maybeAccept( arrayType->base.get(), *visitor );
    526527                }
     
    545546                void Mangler_new::postvisit( const ast::FunctionType * functionType ) {
    546547                        printQualifiers( functionType );
    547                         mangleName << Encoding::function;
     548                        mangleName += Encoding::function;
    548549                        // turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
    549550                        // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
     
    551552                        GuardValue( inFunctionType );
    552553                        inFunctionType = true;
    553                         std::vector< ast::ptr< ast::Type > > returnTypes = getTypes( functionType->returns );
    554                         if (returnTypes.empty()) mangleName << Encoding::void_t;
    555                         else accept_each( returnTypes, *visitor );
    556                         mangleName << "_";
    557                         std::vector< ast::ptr< ast::Type > > paramTypes = getTypes( functionType->params );
    558                         accept_each( paramTypes, *visitor );
    559                         mangleName << "_";
    560                 }
    561 
    562                 void Mangler_new::mangleRef( const ast::ReferenceToType * refType, std::string prefix ) {
     554                        if (functionType->returns.empty()) mangleName += Encoding::void_t;
     555                        else accept_each( functionType->returns, *visitor );
     556                        mangleName += "_";
     557                        accept_each( functionType->params, *visitor );
     558                        mangleName += "_";
     559                }
     560
     561                void Mangler_new::mangleRef( const ast::BaseInstType * refType, std::string prefix ) {
    563562                        printQualifiers( refType );
    564563
    565                         mangleName << prefix << refType->name.length() << refType->name;
     564                        mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
    566565
    567566                        if ( mangleGenericParams ) {
    568567                                if ( ! refType->params.empty() ) {
    569                                         mangleName << "_";
     568                                        mangleName += "_";
    570569                                        for ( const ast::Expr * param : refType->params ) {
    571570                                                auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
     
    573572                                                maybeAccept( paramType->type.get(), *visitor );
    574573                                        }
    575                                         mangleName << "_";
     574                                        mangleName += "_";
    576575                                }
    577576                        }
     
    602601                                // are first found and prefixing with the appropriate encoding for the type class.
    603602                                assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
    604                                 mangleName << Encoding::typeVariables[varNum->second.second] << varNum->second.first;
     603                                mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
    605604                        } // if
    606605                }
     
    608607                void Mangler_new::postvisit( const ast::TraitInstType * inst ) {
    609608                        printQualifiers( inst );
    610                         mangleName << inst->name.size() << inst->name;
     609                        mangleName += std::to_string( inst->name.size() ) + inst->name;
    611610                }
    612611
    613612                void Mangler_new::postvisit( const ast::TupleType * tupleType ) {
    614613                        printQualifiers( tupleType );
    615                         mangleName << Encoding::tuple << tupleType->types.size();
     614                        mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
    616615                        accept_each( tupleType->types, *visitor );
    617616                }
     
    620619                        printQualifiers( varArgsType );
    621620                        static const std::string vargs = "__builtin_va_list";
    622                         mangleName << Encoding::type << vargs.size() << vargs;
     621                        mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
    623622                }
    624623
    625624                void Mangler_new::postvisit( const ast::ZeroType * ) {
    626                         mangleName << Encoding::zero;
     625                        mangleName += Encoding::zero;
    627626                }
    628627
    629628                void Mangler_new::postvisit( const ast::OneType * ) {
    630                         mangleName << Encoding::one;
     629                        mangleName += Encoding::one;
    631630                }
    632631
     
    636635                                // N marks the start of a qualified type
    637636                                inQualifiedType = true;
    638                                 mangleName << Encoding::qualifiedTypeStart;
     637                                mangleName += Encoding::qualifiedTypeStart;
    639638                        }
    640639                        maybeAccept( qualType->parent.get(), *visitor );
     
    643642                                // E marks the end of a qualified type
    644643                                inQualifiedType = false;
    645                                 mangleName << Encoding::qualifiedTypeEnd;
     644                                mangleName += Encoding::qualifiedTypeEnd;
    646645                        }
    647646                }
     
    655654                        assertf(false, "Mangler_new should not visit typedecl: %s", toCString(decl));
    656655                        assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
    657                         mangleName << Encoding::typeVariables[ decl->kind ] << ( decl->name.length() ) << decl->name;
     656                        mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
    658657                }
    659658
     
    667666                        // skip if not including qualifiers
    668667                        if ( typeMode ) return;
    669                         if ( auto ptype = dynamic_cast< const ast::ParameterizedType * >(type) ) {
     668                        if ( auto ptype = dynamic_cast< const ast::FunctionType * >(type) ) {
    670669                                if ( ! ptype->forall.empty() ) {
    671670                                        std::list< std::string > assertionNames;
    672671                                        int dcount = 0, fcount = 0, vcount = 0, acount = 0;
    673                                         mangleName << Encoding::forall;
    674                                         for ( const ast::TypeDecl * decl : ptype->forall ) {
     672                                        mangleName += Encoding::forall;
     673                                        for ( auto & decl : ptype->forall ) {
    675674                                                switch ( decl->kind ) {
    676675                                                case ast::TypeDecl::Kind::Dtype:
     
    687686                                                } // switch
    688687                                                varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
    689                                                 for ( const ast::DeclWithType * assert : decl->assertions ) {
    690                                                         ast::Pass<Mangler_new> sub_mangler(
    691                                                                 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    692                                                         assert->accept( sub_mangler );
    693                                                         assertionNames.push_back( sub_mangler.pass.get_mangleName() );
    694                                                         acount++;
    695                                                 } // for
    696688                                        } // for
    697                                         mangleName << dcount << "_" << fcount << "_" << vcount << "_" << acount << "_";
    698                                         std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    699                                         mangleName << "_";
     689                                        for ( auto & assert : ptype->assertions ) {
     690                                                ast::Pass<Mangler_new> sub_mangler(
     691                                                        mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
     692                                                assert->var->accept( sub_mangler );
     693                                                assertionNames.push_back( sub_mangler.core.get_mangleName() );
     694                                                acount++;
     695                                        } // for
     696                                        mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
     697                                        for(const auto & a : assertionNames) mangleName += a;
     698//                                      std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
     699                                        mangleName += "_";
    700700                                } // if
    701701                        } // if
     
    703703                                // these qualifiers do not distinguish the outermost type of a function parameter
    704704                                if ( type->is_const() ) {
    705                                         mangleName << Encoding::qualifiers.at(Type::Const);
     705                                        mangleName += Encoding::qualifiers.at(Type::Const);
    706706                                } // if
    707707                                if ( type->is_volatile() ) {
    708                                         mangleName << Encoding::qualifiers.at(Type::Volatile);
     708                                        mangleName += Encoding::qualifiers.at(Type::Volatile);
    709709                                } // if
    710710                                // Removed due to restrict not affecting function compatibility in GCC
    711711                                // if ( type->get_isRestrict() ) {
    712                                 //      mangleName << "E";
     712                                //      mangleName += "E";
    713713                                // } // if
    714714                                if ( type->is_atomic() ) {
    715                                         mangleName << Encoding::qualifiers.at(Type::Atomic);
     715                                        mangleName += Encoding::qualifiers.at(Type::Atomic);
    716716                                } // if
    717717                        }
    718718                        if ( type->is_mutex() ) {
    719                                 mangleName << Encoding::qualifiers.at(Type::Mutex);
     719                                mangleName += Encoding::qualifiers.at(Type::Mutex);
    720720                        } // if
    721721                        if ( inFunctionType ) {
  • src/SymTab/Validate.cc

    r3c64c668 r58fe85a  
    6464#include "Common/UniqueName.h"         // for UniqueName
    6565#include "Common/utility.h"            // for operator+, cloneAll, deleteAll
     66#include "CompilationState.h"          // skip some passes in new-ast build
    6667#include "Concurrency/Keywords.h"      // for applyKeywords
    6768#include "FixFunction.h"               // for FixFunction
     
    270271        };
    271272
    272         struct ArrayLength : public WithIndexer {
     273        struct InitializerLength {
    273274                /// for array types without an explicit length, compute the length and store it so that it
    274275                /// is known to the rest of the phases. For example,
     
    281282
    282283                void previsit( ObjectDecl * objDecl );
     284        };
     285
     286        struct ArrayLength : public WithIndexer {
     287                static void computeLength( std::list< Declaration * > & translationUnit );
     288
    283289                void previsit( ArrayType * arrayType );
    284290        };
     
    368374                                mutateAll( translationUnit, compoundliteral );
    369375                        });
    370                         Stats::Time::TimeBlock("Resolve With Expressions", [&]() {
    371                                 ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
    372                         });
     376                        if (!useNewAST) {
     377                                Stats::Time::TimeBlock("Resolve With Expressions", [&]() {
     378                                        ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
     379                                });
     380                        }
    373381                }
    374382                {
    375383                        Stats::Heap::newPass("validate-F");
    376384                        Stats::Time::BlockGuard guard("validate-F");
    377                         Stats::Time::TimeCall("Fix Object Type",
    378                                 FixObjectType::fix, translationUnit);
    379                         Stats::Time::TimeCall("Array Length",
    380                                 ArrayLength::computeLength, translationUnit);
     385                        if (!useNewAST) {
     386                                Stats::Time::TimeCall("Fix Object Type",
     387                                        FixObjectType::fix, translationUnit);
     388                        }
     389                        Stats::Time::TimeCall("Initializer Length",
     390                                InitializerLength::computeLength, translationUnit);
     391                        if (!useNewAST) {
     392                                Stats::Time::TimeCall("Array Length",
     393                                        ArrayLength::computeLength, translationUnit);
     394                        }
    381395                        Stats::Time::TimeCall("Find Special Declarations",
    382396                                Validate::findSpecialDecls, translationUnit);
    383397                        Stats::Time::TimeCall("Fix Label Address",
    384398                                mutateAll<LabelAddressFixer>, translationUnit, labelAddrFixer);
    385                         Stats::Time::TimeCall("Handle Attributes",
    386                                 Validate::handleAttributes, translationUnit);
     399                        if (!useNewAST) {
     400                                Stats::Time::TimeCall("Handle Attributes",
     401                                        Validate::handleAttributes, translationUnit);
     402                        }
    387403                }
    388404        }
     
    960976        }
    961977
     978        static bool isNonParameterAttribute( Attribute * attr ) {
     979                static const std::vector<std::string> bad_names = {
     980                        "aligned", "__aligned__",
     981                };
     982                for ( auto name : bad_names ) {
     983                        if ( name == attr->name ) {
     984                                return true;
     985                        }
     986                }
     987                return false;
     988        }
     989
    962990        Type * ReplaceTypedef::postmutate( TypeInstType * typeInst ) {
    963991                // instances of typedef types will come here. If it is an instance
     
    968996                        ret->location = typeInst->location;
    969997                        ret->get_qualifiers() |= typeInst->get_qualifiers();
    970                         // attributes are not carried over from typedef to function parameters/return values
    971                         if ( ! inFunctionType ) {
    972                                 ret->attributes.splice( ret->attributes.end(), typeInst->attributes );
    973                         } else {
    974                                 deleteAll( ret->attributes );
    975                                 ret->attributes.clear();
    976                         }
     998                        // GCC ignores certain attributes if they arrive by typedef, this mimics that.
     999                        if ( inFunctionType ) {
     1000                                ret->attributes.remove_if( isNonParameterAttribute );
     1001                        }
     1002                        ret->attributes.splice( ret->attributes.end(), typeInst->attributes );
    9771003                        // place instance parameters on the typedef'd type
    9781004                        if ( ! typeInst->parameters.empty() ) {
     
    13151341        }
    13161342
     1343        void InitializerLength::computeLength( std::list< Declaration * > & translationUnit ) {
     1344                PassVisitor<InitializerLength> len;
     1345                acceptAll( translationUnit, len );
     1346        }
     1347
    13171348        void ArrayLength::computeLength( std::list< Declaration * > & translationUnit ) {
    13181349                PassVisitor<ArrayLength> len;
     
    13201351        }
    13211352
    1322         void ArrayLength::previsit( ObjectDecl * objDecl ) {
     1353        void InitializerLength::previsit( ObjectDecl * objDecl ) {
    13231354                if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->type ) ) {
    13241355                        if ( at->dimension ) return;
     
    13741405        /// Replaces enum types by int, and function/array types in function parameter and return
    13751406        /// lists by appropriate pointers
     1407        /*
    13761408        struct EnumAndPointerDecay_new {
    13771409                const ast::EnumDecl * previsit( const ast::EnumDecl * enumDecl ) {
     
    14241456                }
    14251457        };
     1458        */
    14261459
    14271460        /// expand assertions from a trait instance, performing appropriate type variable substitutions
     
    14421475        }
    14431476
     1477        /*
     1478
    14441479        /// Associates forward declarations of aggregates with their definitions
    14451480        class LinkReferenceToTypes_new final
     
    15081543                }
    15091544
    1510                 void checkGenericParameters( const ast::ReferenceToType * inst ) {
     1545                void checkGenericParameters( const ast::BaseInstType * inst ) {
    15111546                        for ( const ast::Expr * param : inst->params ) {
    15121547                                if ( ! dynamic_cast< const ast::TypeExpr * >( param ) ) {
     
    17721807                static const node_t * forallFixer(
    17731808                        const CodeLocation & loc, const node_t * node,
    1774                         ast::ParameterizedType::ForallList parent_t::* forallField
     1809                        ast::FunctionType::ForallList parent_t::* forallField
    17751810                ) {
    17761811                        for ( unsigned i = 0; i < (node->* forallField).size(); ++i ) {
     
    18231858                }
    18241859        };
     1860        */
    18251861} // anonymous namespace
    18261862
     1863/*
    18271864const ast::Type * validateType(
    18281865                const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ) {
    1829         ast::Pass< EnumAndPointerDecay_new > epc;
     1866        // ast::Pass< EnumAndPointerDecay_new > epc;
    18301867        ast::Pass< LinkReferenceToTypes_new > lrt{ loc, symtab };
    18311868        ast::Pass< ForallPointerDecay_new > fpd{ loc };
    18321869
    1833         return type->accept( epc )->accept( lrt )->accept( fpd );
     1870        return type->accept( lrt )->accept( fpd );
    18341871}
     1872*/
    18351873
    18361874} // namespace SymTab
  • src/SymTab/module.mk

    r3c64c668 r58fe85a  
    1717SRC_SYMTAB = \
    1818      SymTab/Autogen.cc \
     19      SymTab/Autogen.h \
    1920      SymTab/FixFunction.cc \
     21      SymTab/FixFunction.h \
    2022      SymTab/Indexer.cc \
     23      SymTab/Indexer.h \
    2124      SymTab/Mangler.cc \
    2225      SymTab/ManglerCommon.cc \
    23       SymTab/Validate.cc
     26      SymTab/Mangler.h \
     27      SymTab/Validate.cc \
     28      SymTab/Validate.h
    2429
    2530SRC += $(SRC_SYMTAB)
  • src/SynTree/AggregateDecl.cc

    r3c64c668 r58fe85a  
    2121#include "Common/utility.h"      // for printAll, cloneAll, deleteAll
    2222#include "Declaration.h"         // for AggregateDecl, TypeDecl, Declaration
     23#include "Expression.h"
    2324#include "Initializer.h"
    2425#include "LinkageSpec.h"         // for Spec, linkageName, Cforall
     
    8889const char * StructDecl::typeString() const { return aggrString( kind ); }
    8990
     91StructInstType * StructDecl::makeInst( std::list< Expression * > const & new_parameters ) {
     92        std::list< Expression * > copy_parameters;
     93        cloneAll( new_parameters, copy_parameters );
     94        return makeInst( move( copy( copy_parameters ) ) );
     95}
     96
     97StructInstType * StructDecl::makeInst( std::list< Expression * > && new_parameters ) {
     98        assert( parameters.size() == new_parameters.size() );
     99        StructInstType * type = new StructInstType( noQualifiers, this );
     100        type->parameters = std::move( new_parameters );
     101        return type;
     102}
     103
    90104const char * UnionDecl::typeString() const { return aggrString( Union ); }
    91105
  • src/SynTree/ApplicationExpr.cc

    r3c64c668 r58fe85a  
    3434
    3535ParamEntry::ParamEntry( const ParamEntry &other ) :
    36                 decl( other.decl ), declptr( maybeClone( other.declptr ) ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
     36                decl( other.decl ), declptr( other.declptr ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
    3737}
    3838
    3939ParamEntry::~ParamEntry() {
    40         delete declptr;
     40        // delete declptr;
    4141        delete actualType;
    4242        delete formalType;
  • src/SynTree/Declaration.h

    r3c64c668 r58fe85a  
    181181  public:
    182182        Type * base;
    183         std::list< TypeDecl * > parameters;
    184183        std::list< DeclarationWithType * > assertions;
    185184
     
    190189        Type * get_base() const { return base; }
    191190        void set_base( Type * newValue ) { base = newValue; }
    192         std::list< TypeDecl* > & get_parameters() { return parameters; }
    193191        std::list< DeclarationWithType * >& get_assertions() { return assertions; }
    194192
     
    302300
    303301        bool is_coroutine() { return kind == Coroutine; }
    304         bool is_monitor() { return kind == Monitor; }
    305         bool is_thread() { return kind == Thread; }
     302        bool is_generator() { return kind == Generator; }
     303        bool is_monitor  () { return kind == Monitor  ; }
     304        bool is_thread   () { return kind == Thread   ; }
     305
     306        // Make a type instance of this declaration.
     307        StructInstType * makeInst( std::list< Expression * > const & parameters );
     308        StructInstType * makeInst( std::list< Expression * > && parameters );
    306309
    307310        virtual StructDecl * clone() const override { return new StructDecl( *this ); }
  • src/SynTree/Expression.cc

    r3c64c668 r58fe85a  
    3030#include "Type.h"                    // for Type, BasicType, Type::Qualifiers
    3131#include "TypeSubstitution.h"        // for TypeSubstitution
     32#include "CompilationState.h"        // for deterministic_output
    3233
    3334#include "GenPoly/Lvalue.h"
     
    7071        printInferParams( inferParams, os, indent+1, 0 );
    7172
     73        if ( result ) {
     74                os << std::endl << indent << "with resolved type:" << std::endl;
     75                os << (indent+1);
     76                result->print( os, indent+1 );
     77        }
     78
    7279        if ( env ) {
    7380                os << std::endl << indent << "... with environment:" << std::endl;
     
    293300}
    294301
    295 KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {
    296 }
    297 
    298 KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {
    299 }
     302KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {}
     303KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target, const KeywordCastExpr::Concrete & concrete_target ) : Expression(), arg(arg), target( target ), concrete_target(concrete_target) {}
     304
     305KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {}
    300306
    301307KeywordCastExpr::~KeywordCastExpr() {
  • src/SynTree/Expression.h

    r3c64c668 r58fe85a  
    163163};
    164164
     165/// VariableExpr represents an expression that simply refers to the value of a named variable.
     166/// Does not take ownership of var.
     167class VariableExpr : public Expression {
     168  public:
     169        DeclarationWithType * var;
     170
     171        VariableExpr();
     172        VariableExpr( DeclarationWithType * var );
     173        VariableExpr( const VariableExpr & other );
     174        virtual ~VariableExpr();
     175
     176        bool get_lvalue() const final;
     177
     178        DeclarationWithType * get_var() const { return var; }
     179        void set_var( DeclarationWithType * newValue ) { var = newValue; }
     180
     181        static VariableExpr * functionPointer( FunctionDecl * decl );
     182
     183        virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }
     184        virtual void accept( Visitor & v ) override { v.visit( this ); }
     185        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     186        virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
     187        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     188};
     189
    165190// The following classes are used to represent expression types that cannot be converted into
    166191// function-call format.
     
    206231  public:
    207232        Expression * arg;
    208         bool isGenerated = true; // cast generated implicitly by code generation or explicit in program
     233
     234        // Inidicates cast is introduced by the CFA type system.
     235        // true for casts that the resolver introduces to force a return type
     236        // false for casts from user code
     237        // false for casts from desugaring advanced CFA features into simpler CFA
     238        // example
     239        //   int * p;     // declaration
     240        //   (float *) p; // use, with subject cast
     241        // subject cast isGenerated means we are considering an interpretation with a type mismatch
     242        // subject cast not isGenerated means someone in charge wants it that way
     243        bool isGenerated = true;
    209244
    210245        CastExpr( Expression * arg, bool isGenerated = true );
     
    238273
    239274        KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target );
     275        KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target, const Concrete & concrete_target );
    240276        KeywordCastExpr( const KeywordCastExpr & other );
    241277        virtual ~KeywordCastExpr();
     
    312348
    313349        virtual MemberExpr * clone() const override { return new MemberExpr( * this ); }
    314         virtual void accept( Visitor & v ) override { v.visit( this ); }
    315         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    316         virtual Expression * acceptMutator( Mutator & m ) override { return m.mutate( this ); }
    317         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    318 };
    319 
    320 /// VariableExpr represents an expression that simply refers to the value of a named variable.
    321 /// Does not take ownership of var.
    322 class VariableExpr : public Expression {
    323   public:
    324         DeclarationWithType * var;
    325 
    326         VariableExpr();
    327         VariableExpr( DeclarationWithType * var );
    328         VariableExpr( const VariableExpr & other );
    329         virtual ~VariableExpr();
    330 
    331         bool get_lvalue() const final;
    332 
    333         DeclarationWithType * get_var() const { return var; }
    334         void set_var( DeclarationWithType * newValue ) { var = newValue; }
    335 
    336         static VariableExpr * functionPointer( FunctionDecl * decl );
    337 
    338         virtual VariableExpr * clone() const override { return new VariableExpr( * this ); }
    339350        virtual void accept( Visitor & v ) override { v.visit( this ); }
    340351        virtual void accept( Visitor & v ) const override { v.visit( this ); }
  • src/SynTree/LinkageSpec.cc

    r3c64c668 r58fe85a  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:22:09 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 15:02:29 2019
    13 // Update Count     : 28
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Mar  2 16:13:00 2020
     13// Update Count     : 29
    1414//
    1515
     
    2020
    2121#include "LinkageSpec.h"
     22#include "Common/CodeLocation.h"
    2223#include "Common/SemanticError.h"
    2324
  • src/SynTree/LinkageSpec.h

    r3c64c668 r58fe85a  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:24:28 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 16 15:03:43 2019
    13 // Update Count     : 20
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Mar  2 16:13:00 2020
     13// Update Count     : 21
    1414//
    1515
     
    1818#include <string>
    1919
    20 #include "Common/CodeLocation.h"
     20struct CodeLocation;
    2121
    2222namespace LinkageSpec {
  • src/SynTree/Mutator.h

    r3c64c668 r58fe85a  
    5151        virtual Statement * mutate( CatchStmt * catchStmt ) = 0;
    5252        virtual Statement * mutate( FinallyStmt * catchStmt ) = 0;
     53        virtual Statement * mutate( SuspendStmt * suspendStmt ) = 0;
    5354        virtual Statement * mutate( WaitForStmt * waitforStmt ) = 0;
    5455        virtual Declaration * mutate( WithStmt * withStmt ) = 0;
  • src/SynTree/NamedTypeDecl.cc

    r3c64c668 r58fe85a  
    2222#include "LinkageSpec.h"         // for Spec, Cforall, linkageName
    2323#include "Type.h"                // for Type, Type::StorageClasses
     24#include "CompilationState.h"
    2425
    2526NamedTypeDecl::NamedTypeDecl( const std::string &name, Type::StorageClasses scs, Type *base )
     
    2829NamedTypeDecl::NamedTypeDecl( const NamedTypeDecl &other )
    2930        : Parent( other ), base( maybeClone( other.base ) ) {
    30         cloneAll( other.parameters, parameters );
    3131        cloneAll( other.assertions, assertions );
    3232}
     
    3434NamedTypeDecl::~NamedTypeDecl() {
    3535        delete base;
    36         deleteAll( parameters );
    3736        deleteAll( assertions );
    3837}
     
    4140        using namespace std;
    4241
    43         if ( name != "" ) os << name << ": ";
     42        if ( ! name.empty() ) {
     43                if( deterministic_output && isUnboundType(name) ) os << "[unbound]:";
     44                else os << name << ": ";
     45        }
    4446
    4547        if ( linkage != LinkageSpec::Cforall ) {
     
    5153                os << " for ";
    5254                base->print( os, indent+1 );
    53         } // if
    54         if ( ! parameters.empty() ) {
    55                 os << endl << indent << "... with parameters" << endl;
    56                 printAll( parameters, os, indent+1 );
    5755        } // if
    5856        if ( ! assertions.empty() ) {
     
    7270                base->print( os, indent+1 );
    7371        } // if
    74         if ( ! parameters.empty() ) {
    75                 os << endl << indent << "... with parameters" << endl;
    76                 printAll( parameters, os, indent+1 );
    77         } // if
    7872}
    7973
  • src/SynTree/ReferenceToType.cc

    r3c64c668 r58fe85a  
    2424#include "Type.h"             // for TypeInstType, StructInstType, UnionInstType
    2525#include "TypeSubstitution.h" // for TypeSubstitution
     26#include "CompilationState.h"
    2627
    2728class Attribute;
     
    205206
    206207        Type::print( os, indent );
    207         os << "instance of " << typeString() << " " << get_name() << " (" << ( isFtype ? "" : "not" ) << " function type)";
     208        os << "instance of " << typeString() << " ";
     209        const auto & name_ = get_name();
     210        if( deterministic_output && isUnboundType(name) ) os << "[unbound]";
     211        else os << name;
     212        os << " (" << ( isFtype ? "" : "not" ) << " function type)";
    208213        if ( ! parameters.empty() ) {
    209214                os << endl << indent << "... with parameters" << endl;
  • src/SynTree/Statement.cc

    r3c64c668 r58fe85a  
    420420}
    421421
     422SuspendStmt::SuspendStmt( const SuspendStmt & other )
     423        : Statement( other )
     424        , then( maybeClone(other.then) )
     425{}
     426
     427SuspendStmt::~SuspendStmt() {
     428        delete then;
     429}
     430
     431void SuspendStmt::print( std::ostream & os, Indenter indent ) const {
     432        os << "Suspend Statement";
     433        switch (type) {
     434                case None     : os << " with implicit target"; break;
     435                case Generator: os << " for generator"       ; break;
     436                case Coroutine: os << " for coroutine"       ; break;
     437        }
     438        os << endl;
     439        indent += 1;
     440
     441        if(then) {
     442                os << indent << " with post statement :" << endl;
     443                then->print( os, indent + 1);
     444        }
     445}
     446
    422447WaitForStmt::WaitForStmt() : Statement() {
    423448        timeout.time      = nullptr;
  • src/SynTree/Statement.h

    r3c64c668 r58fe85a  
    422422};
    423423
     424class SuspendStmt : public Statement {
     425  public:
     426        CompoundStmt * then = nullptr;
     427        enum Type { None, Coroutine, Generator } type = None;
     428
     429        SuspendStmt() = default;
     430        SuspendStmt( const SuspendStmt & );
     431        virtual ~SuspendStmt();
     432
     433        virtual SuspendStmt * clone() const override { return new SuspendStmt( *this ); }
     434        virtual void accept( Visitor & v ) override { v.visit( this ); }
     435        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     436        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     437        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     438};
     439
    424440class WaitForStmt : public Statement {
    425441  public:
     
    502518class ImplicitCtorDtorStmt : public Statement {
    503519  public:
    504         // Non-owned pointer to the constructor/destructor statement
     520        // the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere
    505521        Statement * callStmt;
    506522
  • src/SynTree/SynTree.h

    r3c64c668 r58fe85a  
    5454class CatchStmt;
    5555class FinallyStmt;
     56class SuspendStmt;
    5657class WaitForStmt;
    5758class WithStmt;
  • src/SynTree/Type.cc

    r3c64c668 r58fe85a  
    156156const Type::Qualifiers noQualifiers;
    157157
     158bool isUnboundType(const Type * type) {
     159        if (auto typeInst = dynamic_cast<const TypeInstType *>(type)) {
     160                // xxx - look for a type name produced by renameTyVars.
     161
     162                // TODO: once TypeInstType representation is updated, it should properly check
     163                // if the context id is filled. this is a temporary hack for now
     164                return isUnboundType(typeInst->name);
     165        }
     166        return false;
     167}
     168
     169bool isUnboundType(const std::string & tname) {
     170        // xxx - look for a type name produced by renameTyVars.
     171
     172        // TODO: once TypeInstType representation is updated, it should properly check
     173        // if the context id is filled. this is a temporary hack for now
     174        if (std::count(tname.begin(), tname.end(), '_') >= 3) {
     175                return true;
     176        }
     177        return false;
     178}
     179
    158180// Local Variables: //
    159181// tab-width: 4 //
  • src/SynTree/Type.h

    r3c64c668 r58fe85a  
    733733};
    734734
     735
     736bool isUnboundType(const Type * type);
     737bool isUnboundType(const std::string & tname);
     738
    735739// Local Variables: //
    736740// tab-width: 4 //
  • src/SynTree/TypeDecl.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 15:26:14 2019
    13 // Update Count     : 21
     12// Last Modified On : Thu Oct  8 18:18:55 2020
     13// Update Count     : 22
    1414//
    1515
     
    2121#include "Type.h"            // for Type, Type::StorageClasses
    2222
    23 TypeDecl::TypeDecl( const std::string & name, Type::StorageClasses scs, Type * type, Kind kind, bool sized, Type * init ) : Parent( name, scs, type ), kind( kind ), sized( kind == Ttype || sized ), init( init ) {
     23TypeDecl::TypeDecl( const std::string & name, Type::StorageClasses scs, Type * type, Kind kind, bool sized, Type * init ) :
     24        Parent( name, scs, type ), kind( kind ), sized( kind == Ttype || sized ), init( init ) {
    2425}
    2526
  • src/SynTree/Visitor.h

    r3c64c668 r58fe85a  
    7878        virtual void visit( FinallyStmt * node ) { visit( const_cast<const FinallyStmt *>(node) ); }
    7979        virtual void visit( const FinallyStmt * finallyStmt ) = 0;
     80        virtual void visit( SuspendStmt * node ) { visit( const_cast<const SuspendStmt *>(node) ); }
     81        virtual void visit( const SuspendStmt * suspendStmt ) = 0;
    8082        virtual void visit( WaitForStmt * node ) { visit( const_cast<const WaitForStmt *>(node) ); }
    8183        virtual void visit( const WaitForStmt * waitforStmt ) = 0;
  • src/SynTree/module.mk

    r3c64c668 r58fe85a  
    2020      SynTree/ApplicationExpr.cc \
    2121      SynTree/ArrayType.cc \
     22      SynTree/Attribute.cc \
     23      SynTree/Attribute.h \
    2224      SynTree/AttrType.cc \
    23       SynTree/Attribute.cc \
     25      SynTree/BaseSyntaxNode.h \
    2426      SynTree/BasicType.cc \
    2527      SynTree/CommaExpr.cc \
    2628      SynTree/CompoundStmt.cc \
    2729      SynTree/Constant.cc \
     30      SynTree/Constant.h \
     31      SynTree/Declaration.cc \
     32      SynTree/Declaration.h \
     33      SynTree/DeclarationWithType.cc \
    2834      SynTree/DeclReplacer.cc \
     35      SynTree/DeclReplacer.h \
    2936      SynTree/DeclStmt.cc \
    30       SynTree/Declaration.cc \
    31       SynTree/DeclarationWithType.cc \
    3237      SynTree/Expression.cc \
     38      SynTree/Expression.h \
    3339      SynTree/FunctionDecl.cc \
    3440      SynTree/FunctionType.cc \
    3541      SynTree/Initializer.cc \
     42      SynTree/Initializer.h \
     43      SynTree/Label.h \
    3644      SynTree/LinkageSpec.cc \
     45      SynTree/LinkageSpec.h \
     46      SynTree/Mutator.h \
    3747      SynTree/NamedTypeDecl.cc \
    3848      SynTree/ObjectDecl.cc \
     
    4151      SynTree/ReferenceType.cc \
    4252      SynTree/Statement.cc \
     53      SynTree/Statement.h \
     54      SynTree/SynTree.h \
    4355      SynTree/TupleExpr.cc \
    4456      SynTree/TupleType.cc \
     
    4658      SynTree/TypeDecl.cc \
    4759      SynTree/TypeExpr.cc \
     60      SynTree/Type.h \
     61      SynTree/TypeofType.cc \
    4862      SynTree/TypeSubstitution.cc \
    49       SynTree/TypeofType.cc \
     63      SynTree/TypeSubstitution.h \
    5064      SynTree/VarArgsType.cc \
     65      SynTree/Visitor.h \
    5166      SynTree/VoidType.cc \
    5267      SynTree/ZeroOneType.cc
  • src/Tuples/Explode.cc

    r3c64c668 r58fe85a  
    129129                        for ( const ast::Expr * expr : tupleExpr->exprs ) {
    130130                                exprs.emplace_back( applyCast( expr, false ) );
    131                                 //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );
    132131                        }
    133132                        if ( first ) {
     
    148147        }
    149148
    150         const ast::Expr * postmutate( const ast::UniqueExpr * node ) {
     149        const ast::Expr * postvisit( const ast::UniqueExpr * node ) {
    151150                // move cast into unique expr so that the unique expr has type T& rather than
    152151                // type T. In particular, this transformation helps with generating the
     
    162161                        castAdded = false;
    163162                        const ast::Type * newType = getReferenceBase( newNode->result );
    164                         return new ast::CastExpr{ newNode->location, node, newType };
     163                        return new ast::CastExpr{ newNode->location, newNode, newType };
    165164                }
    166165                return newNode;
    167166        }
    168167
    169         const ast::Expr * postmutate( const ast::TupleIndexExpr * tupleExpr ) {
     168        const ast::Expr * postvisit( const ast::TupleIndexExpr * tupleExpr ) {
    170169                // tuple index expr needs to be rebuilt to ensure that the type of the
    171170                // field is consistent with the type of the tuple expr, since the field
     
    180179        ast::Pass<CastExploderCore> exploder;
    181180        expr = expr->accept( exploder );
    182         if ( ! exploder.pass.foundUniqueExpr ) {
     181        if ( ! exploder.core.foundUniqueExpr ) {
    183182                expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
    184183        }
  • src/Tuples/Explode.h

    r3c64c668 r58fe85a  
    210210                        }
    211211                        // Cast a reference away to a value-type to allow further explosion.
    212                         if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
     212                        if ( local->result.as< ast::ReferenceType >() ) {
    213213                                local = new ast::CastExpr{ local, tupleType };
    214214                        }
     
    220220                                // delete idx;
    221221                        }
    222                         // delete local;
    223222                }
    224223        } else {
  • src/Tuples/TupleAssignment.cc

    r3c64c668 r58fe85a  
    465465                                        // resolve ctor/dtor for the new object
    466466                                        ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
    467                                                         InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab );
     467                                                        InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms );
    468468                                        // remove environments from subexpressions of stmtExpr
    469469                                        ast::Pass< EnvRemover > rm{ env };
     
    560560                                        // resolve the cast expression so that rhsCand return type is bound by the cast
    561561                                        // type as needed, and transfer the resulting environment
    562                                         ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env };
     562                                        ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env };
    563563                                        finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
    564564                                        assert( finder.candidates.size() == 1 );
     
    609609                                        // explode the LHS so that each field of a tuple-valued expr is assigned
    610610                                        ResolvExpr::CandidateList lhs;
    611                                         explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
     611                                        explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true );
    612612                                        for ( ResolvExpr::CandidateRef & cand : lhs ) {
    613613                                                // each LHS value must be a reference - some come in with a cast, if not
     
    629629                                                        if ( isTuple( rhsCand->expr ) ) {
    630630                                                                // multiple assignment
    631                                                                 explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     631                                                                explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
    632632                                                                matcher.reset(
    633633                                                                        new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     
    648648                                                        // multiple assignment
    649649                                                        ResolvExpr::CandidateList rhs;
    650                                                         explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     650                                                        explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
    651651                                                        matcher.reset(
    652652                                                                new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     
    678678                                )
    679679
    680                                 ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
     680                                ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env };
    681681
    682682                                try {
  • src/Tuples/TupleExpansion.cc

    r3c64c668 r58fe85a  
    323323                std::vector<ast::ptr<ast::Type>> types;
    324324                ast::CV::Qualifiers quals{
    325                         ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
     325                        ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict |
    326326                        ast::CV::Atomic | ast::CV::Mutex };
    327327
  • src/Tuples/Tuples.cc

    r3c64c668 r58fe85a  
    4343        };
    4444        struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
     45                using ImpurityDetector::previsit;
    4546                void previsit( ast::UniqueExpr const * ) {
    4647                        visit_children = false;
     
    5253                ast::Pass<Detector> detector;
    5354                expr->accept( detector );
    54                 return detector.pass.maybeImpure;
     55                return detector.core.maybeImpure;
    5556        }
    5657} // namespace
  • src/Tuples/module.mk

    r3c64c668 r58fe85a  
    1515###############################################################################
    1616
    17 SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \
    18         Tuples/Tuples.cc
    19 SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \
    20         Tuples/Tuples.cc
     17SRC_TUPLES = \
     18        Tuples/Explode.cc \
     19        Tuples/Explode.h \
     20        Tuples/TupleAssignment.cc \
     21        Tuples/TupleExpansion.cc \
     22        Tuples/Tuples.cc \
     23        Tuples/Tuples.h
     24
     25
     26SRC += $(SRC_TUPLES)
     27SRCDEMANGLE += $(SRC_TUPLES)
  • src/Validate/module.mk

    r3c64c668 r58fe85a  
    1515###############################################################################
    1616
    17 SRC += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
    18 SRCDEMANGLE += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
     17SRC += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h
     18SRCDEMANGLE += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h
  • src/Virtual/ExpandCasts.cc

    r3c64c668 r58fe85a  
    1010// Created On       : Mon Jul 24 13:59:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tus Aug  2 14:59:00 2017
    13 // Update Count     : 1
     12// Last Modified On : Fri Jul 31 10:29:00 2020
     13// Update Count     : 4
    1414//
    1515
     
    1818#include <cassert>                 // for assert, assertf
    1919#include <iterator>                // for back_inserter, inserter
    20 #include <map>                     // for map, _Rb_tree_iterator, map<>::ite...
    2120#include <string>                  // for string, allocator, operator==, ope...
    22 #include <utility>                 // for pair
    2321
    2422#include "Common/PassVisitor.h"    // for PassVisitor
     23#include "Common/ScopedMap.h"      // for ScopedMap
    2524#include "Common/SemanticError.h"  // for SemanticError
     25#include "SymTab/Mangler.h"        // for mangleType
    2626#include "SynTree/Declaration.h"   // for ObjectDecl, StructDecl, FunctionDecl
    2727#include "SynTree/Expression.h"    // for VirtualCastExpr, CastExpr, Address...
     
    3131
    3232namespace Virtual {
     33
     34        // Indented until the new ast code gets added.
     35
     36        /// Maps virtual table types the instance for that type.
     37        class VirtualTableMap final {
     38                ScopedMap<std::string, ObjectDecl *> vtable_instances;
     39        public:
     40                void enterScope() {
     41                        vtable_instances.beginScope();
     42                }
     43                void leaveScope() {
     44                        vtable_instances.endScope();
     45                }
     46
     47                ObjectDecl * insert( ObjectDecl * vtableDecl ) {
     48                        std::string const & mangledName = SymTab::Mangler::mangleType( vtableDecl->type );
     49                        ObjectDecl *& value = vtable_instances[ mangledName ];
     50                        if ( value ) {
     51                                if ( vtableDecl->storageClasses.is_extern ) {
     52                                        return nullptr;
     53                                } else if ( ! value->storageClasses.is_extern ) {
     54                                        return value;
     55                                }
     56                        }
     57                        value = vtableDecl;
     58                        return nullptr;
     59                }
     60
     61                ObjectDecl * lookup( const Type * vtableType ) {
     62                        std::string const & mangledName = SymTab::Mangler::mangleType( vtableType );
     63                        const auto it = vtable_instances.find( mangledName );
     64                        return ( vtable_instances.end() == it ) ? nullptr : it->second;
     65                }
     66        };
    3367
    3468        /* Currently virtual depends on the rather brittle name matching between
     
    3973         */
    4074
     75        namespace {
     76
    4177        std::string get_vtable_name( std::string const & name ) {
    4278                return name + "_vtable";
     
    5389        std::string get_vtable_inst_name_root( std::string const & name ) {
    5490                return get_vtable_name_root( name.substr(1, name.size() - 10 ) );
    55         }
    56 
    57         bool is_vtable_name( std::string const & name ) {
    58                 return (name.substr( name.size() - 7 ) == "_vtable" );
    5991        }
    6092
     
    6496        }
    6597
     98        } // namespace
     99
    66100        class VirtualCastCore {
    67         std::map<std::string, ObjectDecl *> vtable_instances;
    68         FunctionDecl *vcast_decl;
    69         StructDecl *pvt_decl;
    70 
    71101                Type * pointer_to_pvt(int level_of_indirection) {
    72102                        Type * type = new StructInstType(
     
    80110        public:
    81111                VirtualCastCore() :
    82                         vtable_instances(), vcast_decl( nullptr ), pvt_decl( nullptr )
     112                        indexer(), vcast_decl( nullptr ), pvt_decl( nullptr )
    83113                {}
    84114
     
    88118
    89119                Expression * postmutate( VirtualCastExpr * castExpr );
     120
     121                VirtualTableMap indexer;
     122        private:
     123                FunctionDecl *vcast_decl;
     124                StructDecl *pvt_decl;
    90125        };
    91126
     
    107142        void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
    108143                if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
    109                         vtable_instances[objectDecl->get_name()] = objectDecl;
    110                 }
    111         }
     144                        if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) {
     145                                std::string msg = "Repeated instance of virtual table, original found at: ";
     146                                msg += existing->location.filename;
     147                                msg += ":" + toString( existing->location.first_line );
     148                                SemanticError( objectDecl->location, msg );
     149                        }
     150                }
     151        }
     152
     153        namespace {
     154
     155        /// Better error locations for generated casts.
     156        CodeLocation castLocation( const VirtualCastExpr * castExpr ) {
     157                if ( castExpr->location.isSet() ) {
     158                        return castExpr->location;
     159                } else if ( castExpr->arg->location.isSet() ) {
     160                        return castExpr->arg->location;
     161                } else if ( castExpr->result->location.isSet() ) {
     162                        return castExpr->result->location;
     163                } else {
     164                        return CodeLocation();
     165                }
     166        }
     167
     168        [[noreturn]] void castError( const VirtualCastExpr * castExpr, std::string const & message ) {
     169                SemanticError( castLocation( castExpr ), message );
     170        }
     171
     172        /// Get the virtual table type used in a virtual cast.
     173        Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
     174                const Type * objectType;
     175                if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
     176                        objectType = target->base;
     177                } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
     178                        objectType = target->base;
     179                } else {
     180                        castError( castExpr, "Virtual cast type must be a pointer or reference type." );
     181                }
     182                assert( objectType );
     183
     184                const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
     185                if ( nullptr == structType ) {
     186                        castError( castExpr, "Virtual cast type must refer to a structure type." );
     187                }
     188                const StructDecl * structDecl = structType->baseStruct;
     189                assert( structDecl );
     190
     191                const ObjectDecl * fieldDecl = nullptr;
     192                if ( 0 < structDecl->members.size() ) {
     193                        const Declaration * memberDecl = structDecl->members.front();
     194                        assert( memberDecl );
     195                        fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
     196                        if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
     197                                fieldDecl = nullptr;
     198                        }
     199                }
     200                if ( nullptr == fieldDecl ) {
     201                        castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
     202                }
     203                const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
     204                if ( nullptr == fieldType ) {
     205                        castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
     206                }
     207                assert( fieldType->base );
     208                auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
     209                assert( virtualStructType );
     210
     211                // Here is the type, but if it is polymorphic it will have lost information.
     212                // (Always a clone so that it may always be deleted.)
     213                StructInstType * virtualType = virtualStructType->clone();
     214                if ( ! structType->parameters.empty() ) {
     215                        deleteAll( virtualType->parameters );
     216                        virtualType->parameters.clear();
     217                        cloneAll( structType->parameters, virtualType->parameters );
     218                }
     219                return virtualType;
     220        }
     221
     222        } // namespace
    112223
    113224        Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
    114                 assertf( castExpr->get_result(), "Virtual Cast target not found before expansion." );
     225                assertf( castExpr->result, "Virtual Cast target not found before expansion." );
    115226
    116227                assert( vcast_decl );
    117228                assert( pvt_decl );
    118229
    119                 // May only cast to a pointer or reference type.
    120                 // A earlier validation should give a syntax error, this is
    121                 // just to make sure errors don't creep during translation.
    122                 // Move to helper with more detailed error messages.
    123                 PointerType * target_type =
    124                         dynamic_cast<PointerType *>( castExpr->get_result() );
    125                 assert( target_type );
    126 
    127                 StructInstType * target_struct =
    128                         dynamic_cast<StructInstType *>( target_type->get_base() );
    129                 assert( target_struct );
    130 
    131                 StructDecl * target_decl = target_struct->get_baseStruct();
    132 
    133                 std::map<std::string, ObjectDecl *>::iterator found =
    134                         vtable_instances.find(
    135                                 get_vtable_inst_name( target_decl->get_name() ) );
    136                 if ( vtable_instances.end() == found ) {
    137                         assertf( false, "virtual table instance not found." );
    138                 }
    139                 ObjectDecl * table = found->second;
     230                const Type * vtable_type = getVirtualTableType( castExpr );
     231                ObjectDecl * table = indexer.lookup( vtable_type );
     232                if ( nullptr == table ) {
     233                        SemanticError( castLocation( castExpr ),
     234                                "Could not find virtual table instance." );
     235                }
    140236
    141237                Expression * result = new CastExpr(
    142                         //new ApplicationExpr(
    143                                 //new AddressExpr( new VariableExpr( vcast_decl ) ),
    144                                 //new CastExpr( new VariableExpr( vcast_decl ),
    145                                 //      new PointerType( noQualifiers,
    146                                 //              vcast_decl->get_type()->clone()
    147                                 //              )
    148                                 //      ),
    149238                        new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    150239                                        new CastExpr(
     
    163252                castExpr->set_result( nullptr );
    164253                delete castExpr;
     254                delete vtable_type;
    165255                return result;
    166256        }
  • src/Virtual/module.mk

    r3c64c668 r58fe85a  
    1515###############################################################################
    1616
    17 SRC += Virtual/ExpandCasts.cc
     17SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \
     18        Virtual/Tables.cc Virtual/Tables.h
     19
     20SRCDEMANGLE += Virtual/Tables.cc
  • src/config.h.in

    r3c64c668 r58fe85a  
    2727/* Location of cfa install. */
    2828#undef CFA_PREFIX
     29
     30/* Sets whether or not to use the new-ast, this is adefault value and can be
     31   overrided by --old-ast and --new-ast */
     32#undef CFA_USE_NEW_AST
    2933
    3034/* Major.Minor */
  • src/main.cc

    r3c64c668 r58fe85a  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb  8 08:33:50 2020
    13 // Update Count     : 633
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Dec  7 15:29:00 2020
     13// Update Count     : 639
    1414//
    1515
     
    3131using namespace std;
    3232
    33 
     33#include "AST/Convert.hpp"
    3434#include "CompilationState.h"
    3535#include "../config.h"                      // for CFA_LIBDIR
     
    4040#include "CodeTools/ResolvProtoDump.h"      // for dumpAsResolvProto
    4141#include "CodeTools/TrackLoc.h"             // for fillLocations
     42#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    4243#include "Common/CompilerError.h"           // for CompilerError
    4344#include "Common/Stats.h"
     
    312313                } // if
    313314
     315                PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) );
    314316                PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
    315317                PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
     
    339341                } // if
    340342
    341                 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
    342                 if ( exprp ) {
    343                         dump( translationUnit );
    344                         return EXIT_SUCCESS;
    345                 } // if
     343                if( useNewAST ) {
     344                        if (Stats::Counters::enabled) {
     345                                ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
     346                                ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New");
     347                        }
     348                        auto transUnit = convert( move( translationUnit ) );
     349                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
     350                        if ( exprp ) {
     351                                translationUnit = convert( move( transUnit ) );
     352                                dump( translationUnit );
     353                                return EXIT_SUCCESS;
     354                        } // if
     355
     356                        forceFillCodeLocations( transUnit );
     357
     358                        PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
     359                        translationUnit = convert( move( transUnit ) );
     360                } else {
     361                        PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
     362                        if ( exprp ) {
     363                                dump( translationUnit );
     364                                return EXIT_SUCCESS;
     365                        }
     366
     367                        PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
     368                }
    346369
    347370                // fix ObjectDecl - replaces ConstructorInit nodes
    348                 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
    349371                if ( ctorinitp ) {
    350372                        dump ( translationUnit );
     
    354376                PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    355377
    356                 PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) );
     378                PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) );
    357379
    358380                PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) );
     
    443465
    444466
    445 static const char optstring[] = ":c:ghlLmNnpP:S:twW:D:";
     467static const char optstring[] = ":c:ghlLmNnpdOAP:S:twW:D:";
    446468
    447469enum { PreludeDir = 128 };
     
    456478        { "no-prelude", no_argument, nullptr, 'n' },
    457479        { "prototypes", no_argument, nullptr, 'p' },
     480        { "deterministic-out", no_argument, nullptr, 'd' },
     481        { "old-ast", no_argument, nullptr, 'O'},
     482        { "new-ast", no_argument, nullptr, 'A'},
    458483        { "print", required_argument, nullptr, 'P' },
    459484        { "prelude-dir", required_argument, nullptr, PreludeDir },
     
    467492
    468493static const char * description[] = {
    469         "diagnostic color: never, always, or auto.",          // -c
    470         "wait for gdb to attach",                             // -g
    471         "print help message",                                 // -h
    472         "generate libcfa.c",                                  // -l
    473         "generate line marks",                                // -L
    474         "do not replace main",                                // -m
    475         "do not generate line marks",                         // -N
    476         "do not read prelude",                                // -n
     494        "diagnostic color: never, always, or auto.",            // -c
     495        "wait for gdb to attach",                                                       // -g
     496        "print help message",                                                           // -h
     497        "generate libcfa.c",                                                            // -l
     498        "generate line marks",                                                          // -L
     499        "do not replace main",                                                          // -m
     500        "do not generate line marks",                                           // -N
     501        "do not read prelude",                                                          // -n
    477502        "generate prototypes for prelude functions",            // -p
    478         "print",                                              // -P
     503        "only print deterministic output",                  // -d
     504        "Use the old-ast",                                                                      // -O
     505        "Use the new-ast",                                                                      // -A
     506        "print",                                                                                        // -P
    479507        "<directory> prelude directory for debug/nodebug",      // no flag
    480508        "<option-list> enable profiling information:\n          counters,heap,time,all,none", // -S
    481         "building cfa standard lib",                          // -t
    482         "",                                                   // -w
    483         "",                                                   // -W
    484         "",                                                   // -D
     509        "building cfa standard lib",                                            // -t
     510        "",                                                                                                     // -w
     511        "",                                                                                                     // -W
     512        "",                                                                                                     // -D
    485513}; // description
    486514
     
    580608                        genproto = true;
    581609                        break;
     610                  case 'd':                                     // don't print non-deterministic output
     611                        deterministic_output = true;
     612                        break;
     613                  case 'O':                                     // don't print non-deterministic output
     614                        useNewAST = false;
     615                        break;
     616                  case 'A':                                     // don't print non-deterministic output
     617                        useNewAST = true;
     618                        break;
    582619                  case 'P':                                                                             // print options
    583620                        for ( int i = 0;; i += 1 ) {
Note: See TracChangeset for help on using the changeset viewer.