Changeset 6054b18 for src


Ignore:
Timestamp:
May 29, 2019, 9:09:30 PM (5 years ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
466fa01
Parents:
c786e1d (diff), d88f8b3b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Location:
src
Files:
2 added
26 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Convert.cpp

    rc786e1d r6054b18  
    1010// Created On       : Thu May 09 15::37::05 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue May 28 12:00:00 2019
    13 // Update Count     : 7
     12// Last Modified On : Wed May 29 17:05:00 2019
     13// Update Count     : 9
    1414//
    1515
     
    2525#include "AST/TypeSubstitution.hpp"
    2626
     27#include "SymTab/Autogen.h"
    2728#include "SynTree/Attribute.h"
    2829#include "SynTree/Declaration.h"
    2930#include "SynTree/TypeSubstitution.h"
     31
     32#include "Validate/FindSpecialDecls.h"
    3033
    3134//================================================================================================
     
    4043        }
    4144};
     45
     46//================================================================================================
     47namespace {
     48
     49// This is to preserve the SymTab::dereferenceOperator hack. It does not (and perhaps should not)
     50// allow us to use the same stratagy in the new ast.
     51ast::FunctionDecl * dereferenceOperator = nullptr;
     52
     53}
    4254
    4355//================================================================================================
     
    154166                        LinkageSpec::Spec( node->linkage.val ),
    155167                        get<FunctionType>().accept1( node->type ),
    156                         get<CompoundStmt>().accept1( node->stmts ),
     168                        {},
    157169                        get<Attribute>().acceptL( node->attributes ),
    158170                        Type::FuncSpecifiers( node->funcSpec.val )
    159171                );
     172                cache.emplace( node, decl );
     173                decl->statements = get<CompoundStmt>().accept1( node->stmts );
    160174                decl->withExprs = get<Expression>().acceptL( node->withExprs );
     175                if ( dereferenceOperator == node ) {
     176                        Validate::dereferenceOperator = decl;
     177                }
    161178                return declWithTypePostamble( decl, node );
    162179        }
     
    871888                );
    872889
    873                 rslt->tempDecls = get<ObjectDecl>().acceptL(node->tempDecls);
    874                 rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls);
    875                 rslt->dtors = get<Expression>().acceptL(node->dtors);
    876 
    877890                auto expr = visitBaseExpr( node, rslt );
    878891                this->node = expr;
     
    14251438                        old->name,
    14261439                        GET_ACCEPT_1(type, FunctionType),
    1427                         GET_ACCEPT_1(statements, CompoundStmt),
     1440                        {},
    14281441                        { old->storageClasses.val },
    14291442                        { old->linkage.val },
     
    14321445                };
    14331446                cache.emplace( old, decl );
     1447                decl->stmts = GET_ACCEPT_1(statements, CompoundStmt);
    14341448                decl->scopeLevel = old->scopeLevel;
    14351449                decl->mangleName = old->mangleName;
     
    14391453
    14401454                this->node = decl;
     1455
     1456                if ( Validate::dereferenceOperator == old ) {
     1457                        dereferenceOperator = decl;
     1458                }
    14411459        }
    14421460
     
    14841502        virtual void visit( EnumDecl * old ) override final {
    14851503                if ( inCache( old ) ) return;
    1486                 auto decl = new ast::UnionDecl(
     1504                auto decl = new ast::EnumDecl(
    14871505                        old->location,
    14881506                        old->name,
     
    15041522        virtual void visit( TraitDecl * old ) override final {
    15051523                if ( inCache( old ) ) return;
    1506                 auto decl = new ast::UnionDecl(
     1524                auto decl = new ast::TraitDecl(
    15071525                        old->location,
    15081526                        old->name,
     
    22652283                );
    22662284
    2267                 rslt->tempDecls = GET_ACCEPT_V(tempDecls, ObjectDecl);
    2268                 rslt->returnDecls = GET_ACCEPT_V(returnDecls, ObjectDecl);
    2269                 rslt->dtors = GET_ACCEPT_V(dtors, Expr);
    2270 
    22712285                this->node = visitBaseExpr( old, rslt );
    22722286        }
  • src/AST/Expr.hpp

    rc786e1d r6054b18  
    530530public:
    531531        ptr<ApplicationExpr> callExpr;
    532         std::vector<ptr<ObjectDecl>> tempDecls;
    533         std::vector<ptr<ObjectDecl>> returnDecls;
    534         std::vector<ptr<Expr>> dtors;
    535532
    536533        ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call )
    537         : Expr( loc, call->result ), tempDecls(), returnDecls(), dtors() { assert( call ); }
     534        : Expr( loc, call->result ) { assert( call ); }
    538535
    539536        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Pass.impl.hpp

    rc786e1d r6054b18  
    13191319                }
    13201320                maybe_accept( node, &ImplicitCopyCtorExpr::callExpr    );
    1321                 maybe_accept( node, &ImplicitCopyCtorExpr::tempDecls   );
    1322                 maybe_accept( node, &ImplicitCopyCtorExpr::returnDecls );
    1323                 maybe_accept( node, &ImplicitCopyCtorExpr::dtors       );
    13241321        )
    13251322
  • src/AST/Print.cpp

    rc786e1d r6054b18  
    10231023                os << "Implicit Copy Constructor Expression:" << endl << indent;
    10241024                safe_print( node->callExpr );
    1025                 os << endl << indent-1 << "... with temporaries:" << endl;
    1026                 printAll( node->tempDecls );
    1027                 os << endl << indent-1 << "... with return temporaries:" << endl;
    1028                 printAll( node->returnDecls );
    10291025                --indent;
    10301026                postprint( node );
  • src/Common/PassVisitor.impl.h

    rc786e1d r6054b18  
    17891789        VISIT_START( node );
    17901790
    1791         indexerScopedAccept( node->result     , *this );
    1792         maybeAccept_impl   ( node->callExpr   , *this );
    1793         maybeAccept_impl   ( node->tempDecls  , *this );
    1794         maybeAccept_impl   ( node->returnDecls, *this );
    1795         maybeAccept_impl   ( node->dtors      , *this );
     1791        indexerScopedAccept( node->result    , *this );
     1792        maybeAccept_impl   ( node->callExpr  , *this );
    17961793
    17971794        VISIT_END( node );
     
    18021799        MUTATE_START( node );
    18031800
    1804         indexerScopedMutate( node->env        , *this );
    1805         indexerScopedMutate( node->result     , *this );
    1806         maybeMutate_impl   ( node->callExpr   , *this );
    1807         maybeMutate_impl   ( node->tempDecls  , *this );
    1808         maybeMutate_impl   ( node->returnDecls, *this );
    1809         maybeMutate_impl   ( node->dtors      , *this );
     1801        indexerScopedMutate( node->env       , *this );
     1802        indexerScopedMutate( node->result    , *this );
     1803        maybeMutate_impl   ( node->callExpr  , *this );
    18101804
    18111805        MUTATE_END( Expression, node );
  • src/ControlStruct/ExceptTranslate.cc

    rc786e1d r6054b18  
    319319                        }
    320320
    321                         block->push_back( handler->get_body() );
    322                         handler->set_body( nullptr );
     321                        block->push_back( handler->body );
     322                        handler->body = nullptr;
    323323
    324324                        std::list<Statement *> caseBody
  • src/GenPoly/Box.cc

    rc786e1d r6054b18  
    657657                                paramExpr = new AddressExpr( paramExpr );
    658658                        } // if
    659                         arg = appExpr->get_args().insert( arg, paramExpr ); // add argument to function call
     659                        arg = appExpr->args.insert( arg, paramExpr ); // add argument to function call
    660660                        arg++;
    661661                        // Build a comma expression to call the function and emulate a normal return.
    662662                        CommaExpr *commaExpr = new CommaExpr( appExpr, retExpr );
    663                         commaExpr->set_env( appExpr->get_env() );
    664                         appExpr->set_env( 0 );
     663                        commaExpr->env = appExpr->env;
     664                        appExpr->env = nullptr;
    665665                        return commaExpr;
    666666                }
     
    708708//                      if ( ! function->get_returnVals().empty() && isPolyType( function->get_returnVals().front()->get_type(), tyVars ) ) {
    709709                        if ( isDynRet( function, tyVars ) ) {
    710                                 ret = addRetParam( appExpr, function->get_returnVals().front()->get_type(), arg );
     710                                ret = addRetParam( appExpr, function->returnVals.front()->get_type(), arg );
    711711                        } // if
    712712                        std::string mangleName = mangleAdapterName( function, tyVars );
     
    715715                        // cast adaptee to void (*)(), since it may have any type inside a polymorphic function
    716716                        Type * adapteeType = new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
    717                         appExpr->get_args().push_front( new CastExpr( appExpr->get_function(), adapteeType ) );
     717                        appExpr->get_args().push_front( new CastExpr( appExpr->function, adapteeType ) );
    718718                        appExpr->set_function( new NameExpr( adapterName ) ); // xxx - result is never set on NameExpr
    719719
  • src/GenPoly/GenPoly.cc

    rc786e1d r6054b18  
    459459
    460460        void addToTyVarMap( TypeDecl * tyVar, TyVarMap &tyVarMap ) {
    461                 // xxx - should this actually be insert?
    462                 tyVarMap[ tyVar->get_name() ] = TypeDecl::Data{ tyVar };
     461                tyVarMap.insert( tyVar->name, TypeDecl::Data{ tyVar } );
    463462        }
    464463
  • src/GenPoly/Lvalue.cc

    rc786e1d r6054b18  
    2121#include "Lvalue.h"
    2222
     23#include "InitTweak/InitTweak.h"
    2324#include "Parser/LinkageSpec.h"          // for Spec, isBuiltin, Intrinsic
    2425#include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
    2526#include "ResolvExpr/Unify.h"            // for unify
    2627#include "ResolvExpr/typeops.h"
    27 #include "SymTab/Autogen.h"
    2828#include "SymTab/Indexer.h"              // for Indexer
    2929#include "SynTree/Declaration.h"         // for Declaration, FunctionDecl
     
    3333#include "SynTree/Type.h"                // for PointerType, Type, FunctionType
    3434#include "SynTree/Visitor.h"             // for Visitor, acceptAll
     35#include "Validate/FindSpecialDecls.h"   // for dereferenceOperator
    3536
    3637#if 0
     
    4445                // TODO: fold this into the general createDeref function??
    4546                Expression * mkDeref( Expression * arg ) {
    46                         if ( SymTab::dereferenceOperator ) {
     47                        if ( Validate::dereferenceOperator ) {
    4748                                // note: reference depth can be arbitrarily deep here, so peel off the outermost pointer/reference, not just pointer because they are effecitvely equivalent in this pass
    48                                 VariableExpr * deref = new VariableExpr( SymTab::dereferenceOperator );
     49                                VariableExpr * deref = new VariableExpr( Validate::dereferenceOperator );
    4950                                deref->result = new PointerType( Type::Qualifiers(), deref->result );
    5051                                Type * base = InitTweak::getPointerBase( arg->result );
     
    353354                        Type * destType = castExpr->result;
    354355                        Type * srcType = castExpr->arg->result;
     356                        assertf( destType, "Cast to no type in: %s", toCString( castExpr ) );
     357                        assertf( srcType, "Cast from no type in: %s", toCString( castExpr ) );
    355358                        int depth1 = destType->referenceDepth();
    356359                        int depth2 = srcType->referenceDepth();
  • src/GenPoly/ScopedSet.h

    rc786e1d r6054b18  
    3838                typedef typename Scope::pointer pointer;
    3939                typedef typename Scope::const_pointer const_pointer;
    40                
     40
    4141                class iterator : public std::iterator< std::bidirectional_iterator_tag,
    4242                                                       value_type > {
     
    7272                                return *this;
    7373                        }
    74                        
     74
    7575                        reference operator* () { return *it; }
    7676                        pointer operator-> () { return it.operator->(); }
     
    104104                        bool operator!= (const iterator &that) { return !( *this == that ); }
    105105
     106                        size_type get_level() const { return i; }
     107
    106108                private:
    107109                        scope_list const *scopes;
     
    180182                        bool operator!= (const const_iterator &that) { return !( *this == that ); }
    181183
     184                        size_type get_level() const { return i; }
     185
    182186                private:
    183187                        scope_list const *scopes;
     
    185189                        size_type i;
    186190                };
    187                
     191
    188192                /// Starts a new scope
    189193                void beginScope() {
     
    222226                        return const_iterator( const_cast< ScopedSet< Value >* >(this)->find( key ) );
    223227                }
    224                
     228
    225229                /// Finds the given key in the outermost scope inside the given scope where it occurs
    226230                iterator findNext( const_iterator &it, const Value &key ) {
     
    242246                        return std::make_pair( iterator(scopes, res.first, scopes.size()-1), res.second );
    243247                }
    244                
     248
    245249        };
    246250} // namespace GenPoly
  • src/InitTweak/FixInit.cc

    rc786e1d r6054b18  
    5454#include "SynTree/Type.h"              // for Type, Type::StorageClasses
    5555#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
     56#include "SynTree/DeclReplacer.h"      // for DeclReplacer
    5657#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
     58#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    5759
    5860bool ctordtorp = false; // print all debug
     
    6668namespace InitTweak {
    6769        namespace {
    68                 typedef std::unordered_map< int, int > UnqCount;
    69 
    7070                struct SelfAssignChecker {
    7171                        void previsit( ApplicationExpr * appExpr );
     
    8080                };
    8181
    82                 struct ResolveCopyCtors final : public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution {
     82                struct ResolveCopyCtors final : public WithStmtsToAdd, public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution, public WithVisitorRef<ResolveCopyCtors> {
    8383                        /// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
    8484                        /// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
    8585                        /// arguments and return value temporaries
    86                         static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount );
    87 
    88                         ResolveCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ) {}
    89 
    90                         void postvisit( ImplicitCopyCtorExpr * impCpCtorExpr );
    91                         void postvisit( StmtExpr * stmtExpr );
    92                         void previsit( UniqueExpr * unqExpr );
    93                         void postvisit( UniqueExpr * unqExpr );
     86                        static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
     87
     88                        Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
     89                        void premutate( StmtExpr * stmtExpr );
     90                        void premutate( UniqueExpr * unqExpr );
    9491
    9592                        /// create and resolve ctor/dtor expression: fname(var, [cpArg])
     
    9895                        bool skipCopyConstruct( Type * type );
    9996                        void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal );
    100                         void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr );
    101 
    102                         UnqCount & unqCount; // count the number of times each unique expr ID appears
    103                         std::unordered_set< int > vars;
     97                        void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr, Expression *& arg );
    10498                };
    10599
     
    162156                        using Parent::previsit;
    163157
    164                         void previsit( ObjectDecl * objDecl );
    165158                        void previsit( FunctionDecl * funcDecl );
    166159
    167                         void previsit( CompoundStmt * compoundStmt );
    168                         void postvisit( CompoundStmt * compoundStmt );
    169                         void previsit( ReturnStmt * returnStmt );
    170160                        void previsit( BranchStmt * stmt );
    171161                private:
     
    185175
    186176                        std::list< Declaration * > staticDtorDecls;
    187                 };
    188 
    189                 class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithConstTypeSubstitution {
    190                   public:
    191                         FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
    192                         /// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, call expression,
    193                         /// and destructors
    194                         static void fixCopyCtors( std::list< Declaration * > &translationUnit, UnqCount & unqCount );
    195 
    196                         Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
    197                         void premutate( StmtExpr * stmtExpr );
    198                         void premutate( UniqueExpr * unqExpr );
    199 
    200                         UnqCount & unqCount;
    201177                };
    202178
     
    236212                        Expression * postmutate( ConstructorExpr * ctorExpr );
    237213                };
     214
     215                struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
     216                        /// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
     217                        static void split( std::list< Declaration * > &translationUnit );
     218
     219                        Statement * postmutate( ExprStmt * stmt );
     220                        void premutate( TupleAssignExpr * expr );
     221                };
    238222        } // namespace
    239223
     
    245229                InitTweak::fixGlobalInit( translationUnit, inLibrary );
    246230
    247                 UnqCount unqCount;
     231                // must happen before ResolveCopyCtors because temporaries have to be inserted into the correct scope
     232                SplitExpressions::split( translationUnit );
    248233
    249234                InsertImplicitCalls::insert( translationUnit );
    250                 ResolveCopyCtors::resolveImplicitCalls( translationUnit, unqCount );
     235
     236                // Needs to happen before ResolveCopyCtors, because argument/return temporaries should not be considered in
     237                // error checking branch statements
    251238                InsertDtors::insert( translationUnit );
     239
     240                ResolveCopyCtors::resolveImplicitCalls( translationUnit );
    252241                FixInit::fixInitializers( translationUnit );
    253 
    254                 // FixCopyCtors must happen after FixInit, so that destructors are placed correctly
    255                 FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
    256 
    257242                GenStructMemberCalls::generate( translationUnit );
    258243
    259                 // xxx - ctor expansion currently has to be after FixCopyCtors, because there is currently a
    260                 // hack in the way untyped assignments are generated, where the first argument cannot have
    261                 // its address taken because of the way codegeneration handles UntypedExpr vs. ApplicationExpr.
    262                 // Thus such assignment exprs must never pushed through expression resolution (and thus should
    263                 // not go through the FixCopyCtors pass), otherwise they will fail -- guaranteed.
    264                 // Also needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
    265                 // don't look right, and a member can be constructed more than once.
     244                // Needs to happen after GenStructMemberCalls, since otherwise member constructors exprs
     245                // don't have the correct form, and a member can be constructed more than once.
    266246                FixCtorExprs::fix( translationUnit );
    267247        }
    268248
    269249        namespace {
     250                /// find and return the destructor used in `input`. If `input` is not a simple destructor call, generate a thunk
     251                /// that wraps the destructor, insert it into `stmtsToAdd` and return the new function declaration
     252                DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * input, std::list< Statement * > & stmtsToAdd ) {
     253                        // unwrap implicit statement wrapper
     254                        Statement * dtor = input;
     255                        if ( ImplicitCtorDtorStmt * implicit = dynamic_cast< ImplicitCtorDtorStmt * >( input ) ) {
     256                                // dtor = implicit->callStmt;
     257                                // implicit->callStmt = nullptr;
     258                        }
     259                        assert( dtor );
     260                        std::list< Expression * > matches;
     261                        collectCtorDtorCalls( dtor, matches );
     262
     263                        if ( dynamic_cast< ExprStmt * >( dtor ) ) {
     264                                // only one destructor call in the expression
     265                                if ( matches.size() == 1 ) {
     266                                        DeclarationWithType * func = getFunction( matches.front() );
     267                                        assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
     268
     269                                        // cleanup argument must be a function, not an object (including function pointer)
     270                                        if ( FunctionDecl * dtorFunc = dynamic_cast< FunctionDecl * > ( func ) ) {
     271                                                if ( dtorFunc->type->forall.empty() ) {
     272                                                        // simple case where the destructor is a monomorphic function call - can simply
     273                                                        // use that function as the cleanup function.
     274                                                        delete dtor;
     275                                                        return func;
     276                                                }
     277                                        }
     278                                }
     279                        }
     280
     281                        // otherwise the cleanup is more complicated - need to build a single argument cleanup function that
     282                        // wraps the more complicated code.
     283                        static UniqueName dtorNamer( "__cleanup_dtor" );
     284                        FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt() );
     285                        stmtsToAdd.push_back( new DeclStmt( dtorFunc ) );
     286
     287                        // the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
     288                        ObjectDecl * thisParam = getParamThis( dtorFunc->type );
     289                        Expression * replacement = new VariableExpr( thisParam );
     290
     291                        Type * base = replacement->result->stripReferences();
     292                        if ( dynamic_cast< ArrayType * >( base ) || dynamic_cast< TupleType * > ( base ) ) {
     293                                // need to cast away reference for array types, since the destructor is generated without the reference type,
     294                                // and for tuple types since tuple indexing does not work directly on a reference
     295                                replacement = new CastExpr( replacement, base->clone() );
     296                        }
     297                        DeclReplacer::replace( dtor, { std::make_pair( objDecl, replacement ) } );
     298                        dtorFunc->statements->push_back( strict_dynamic_cast<Statement *>( dtor ) );
     299
     300                        return dtorFunc;
     301                }
     302
     303                void SplitExpressions::split( std::list< Declaration * > & translationUnit ) {
     304                        PassVisitor<SplitExpressions> splitter;
     305                        mutateAll( translationUnit, splitter );
     306                }
     307
    270308                void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) {
    271309                        PassVisitor<InsertImplicitCalls> inserter;
     
    273311                }
    274312
    275                 void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    276                         PassVisitor<ResolveCopyCtors> resolver( unqCount );
    277                         acceptAll( translationUnit, resolver );
     313                void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) {
     314                        PassVisitor<ResolveCopyCtors> resolver;
     315                        mutateAll( translationUnit, resolver );
    278316                }
    279317
     
    303341                }
    304342
    305                 void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
    306                         PassVisitor<FixCopyCtors> fixer( unqCount );
    307                         mutateAll( translationUnit, fixer );
    308                 }
    309 
    310343                void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
    311344                        PassVisitor<GenStructMemberCalls> warner;
     
    318351                }
    319352
    320                 namespace {
    321                         // Relatively simple structural comparison for expressions, needed to determine
    322                         // if two expressions are "the same" (used to determine if self assignment occurs)
    323                         struct StructuralChecker {
    324                                 Expression * stripCasts( Expression * expr ) {
    325                                         // this might be too permissive. It's possible that only particular casts are relevant.
    326                                         while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
    327                                                 expr = cast->arg;
    328                                         }
    329                                         return expr;
    330                                 }
    331 
    332                                 void previsit( Expression * ) {
    333                                         // anything else does not qualify
    334                                         isSimilar = false;
    335                                 }
    336 
    337                                 template<typename T>
    338                                 T * cast( Expression * node ) {
    339                                         // all expressions need to ignore casts, so this bit has been factored out
    340                                         return dynamic_cast< T * >( stripCasts( node ) );
    341                                 }
    342 
    343                                 // ignore casts
    344                                 void previsit( CastExpr * ) {}
    345 
    346                                 void previsit( MemberExpr * memExpr ) {
    347                                         if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
    348                                                 if ( otherMember->member == memExpr->member ) {
    349                                                         other = otherMember->aggregate;
    350                                                         return;
    351                                                 }
    352                                         }
    353                                         isSimilar = false;
    354                                 }
    355 
    356                                 void previsit( VariableExpr * varExpr ) {
    357                                         if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
    358                                                 if ( otherVar->var == varExpr->var ) {
    359                                                         return;
    360                                                 }
    361                                         }
    362                                         isSimilar = false;
    363                                 }
    364 
    365                                 void previsit( AddressExpr * ) {
    366                                         if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
    367                                                 other = addrExpr->arg;
     353                Statement * SplitExpressions::postmutate( ExprStmt * stmt ) {
     354                        // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
     355                        // in the correct places
     356                        CompoundStmt * ret = new CompoundStmt( { stmt } );
     357                        return ret;
     358                }
     359
     360                void SplitExpressions::premutate( TupleAssignExpr * ) {
     361                        // don't do this within TupleAssignExpr, since it is already broken up into multiple expressions
     362                        visit_children = false;
     363                }
     364
     365                // Relatively simple structural comparison for expressions, needed to determine
     366                // if two expressions are "the same" (used to determine if self assignment occurs)
     367                struct StructuralChecker {
     368                        Expression * stripCasts( Expression * expr ) {
     369                                // this might be too permissive. It's possible that only particular casts are relevant.
     370                                while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
     371                                        expr = cast->arg;
     372                                }
     373                                return expr;
     374                        }
     375
     376                        void previsit( Expression * ) {
     377                                // anything else does not qualify
     378                                isSimilar = false;
     379                        }
     380
     381                        template<typename T>
     382                        T * cast( Expression * node ) {
     383                                // all expressions need to ignore casts, so this bit has been factored out
     384                                return dynamic_cast< T * >( stripCasts( node ) );
     385                        }
     386
     387                        // ignore casts
     388                        void previsit( CastExpr * ) {}
     389
     390                        void previsit( MemberExpr * memExpr ) {
     391                                if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
     392                                        if ( otherMember->member == memExpr->member ) {
     393                                                other = otherMember->aggregate;
    368394                                                return;
    369395                                        }
    370                                         isSimilar = false;
    371                                 }
    372 
    373                                 Expression * other = nullptr;
    374                                 bool isSimilar = true;
    375                         };
    376 
    377                         bool structurallySimilar( Expression * e1, Expression * e2 ) {
    378                                 PassVisitor<StructuralChecker> checker;
    379                                 checker.pass.other = e2;
    380                                 e1->accept( checker );
    381                                 return checker.pass.isSimilar;
    382                         }
     396                                }
     397                                isSimilar = false;
     398                        }
     399
     400                        void previsit( VariableExpr * varExpr ) {
     401                                if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
     402                                        if ( otherVar->var == varExpr->var ) {
     403                                                return;
     404                                        }
     405                                }
     406                                isSimilar = false;
     407                        }
     408
     409                        void previsit( AddressExpr * ) {
     410                                if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
     411                                        other = addrExpr->arg;
     412                                        return;
     413                                }
     414                                isSimilar = false;
     415                        }
     416
     417                        Expression * other = nullptr;
     418                        bool isSimilar = true;
     419                };
     420
     421                bool structurallySimilar( Expression * e1, Expression * e2 ) {
     422                        PassVisitor<StructuralChecker> checker;
     423                        checker.pass.other = e2;
     424                        e1->accept( checker );
     425                        return checker.pass.isSimilar;
    383426                }
    384427
     
    457500                        if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
    458501                                // fix newly generated StmtExpr
    459                                 postvisit( assign->stmtExpr );
     502                                premutate( assign->stmtExpr );
    460503                        }
    461504                        return resolved;
     
    489532                                        // so that the object isn't changed inside of the polymorphic function
    490533                                        if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return;
     534                                        // xxx - leaking tmp
    491535                                }
    492536                        }
     
    496540
    497541                        // replace argument to function call with temporary
    498                         arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
    499                         impCpCtorExpr->tempDecls.push_back( tmp );
    500                         impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
    501                 }
    502 
    503                 void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) {
    504                         impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    505                 }
    506 
    507                 void ResolveCopyCtors::postvisit( ImplicitCopyCtorExpr *impCpCtorExpr ) {
     542                        stmtsToAddBefore.push_back( new DeclStmt( tmp ) );
     543                        arg = cpCtor;
     544                        destructRet( tmp, impCpCtorExpr, arg );
     545
     546                        // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
     547                }
     548
     549                void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * /*impCpCtorExpr*/, Expression *& arg ) {
     550                        // TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
     551                        // check for existing cleanup attribute before adding another(?)
     552                        // need to add __Destructor for _tmp_cp variables as well
     553
     554                        assertf( Validate::dtorStruct && Validate::dtorStruct->members.size() == 2, "Destructor generation requires __Destructor definition." );
     555                        assertf( Validate::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." );
     556
     557                        // generate a __Destructor for ret that calls the destructor
     558                        Expression * dtor = makeCtorDtor( "^?{}", ret );
     559
     560                        // if the chosen destructor is intrinsic, elide the generated dtor handler
     561                        if ( arg && isIntrinsicCallExpr( dtor ) ) {
     562                                arg = new CommaExpr( arg, new VariableExpr( ret ) );
     563                                return;
     564                        }
     565
     566                        if ( ! dtor->env ) dtor->env = maybeClone( env );
     567                        DeclarationWithType * dtorFunc = getDtorFunc( ret, new ExprStmt( dtor ), stmtsToAddBefore );
     568
     569                        StructInstType * dtorStructType = new StructInstType( Type::Qualifiers(), Validate::dtorStruct );
     570                        dtorStructType->parameters.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
     571
     572                        // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     573                        FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
     574                        dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
     575                        Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
     576
     577                        static UniqueName namer( "_ret_dtor" );
     578                        ObjectDecl * retDtor = ObjectDecl::newObject( namer.newName(), dtorStructType, new ListInit( { new SingleInit( new ConstantExpr( Constant::null() ) ), new SingleInit( new CastExpr( new VariableExpr( dtorFunc ), dtorType ) ) } ) );
     579                        retDtor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
     580                        stmtsToAddBefore.push_back( new DeclStmt( retDtor ) );
     581
     582                        if ( arg ) {
     583                                Expression * member = new MemberExpr( strict_dynamic_cast<DeclarationWithType *>( Validate::dtorStruct->members.front() ), new VariableExpr( retDtor ) );
     584                                Expression * object = new CastExpr( new AddressExpr( new VariableExpr( ret ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
     585                                Expression * assign = createBitwiseAssignment( member, object );
     586                                arg = new CommaExpr( new CommaExpr( arg, assign ), new VariableExpr( ret ) );
     587                        }
     588
     589                        // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
     590                }
     591
     592                Expression * ResolveCopyCtors::postmutate( ImplicitCopyCtorExpr *impCpCtorExpr ) {
    508593                        CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
    509594
    510595                        ApplicationExpr * appExpr = impCpCtorExpr->callExpr;
     596                        ObjectDecl * returnDecl = nullptr;
    511597
    512598                        // take each argument and attempt to copy construct it.
     
    517603                        for ( Expression * & arg : appExpr->args ) {
    518604                                Type * formal = nullptr;
    519                                 if ( iter != params.end() ) {
     605                                if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
    520606                                        DeclarationWithType * param = *iter++;
    521607                                        formal = param->get_type();
     
    535621                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    536622                                ret->type->set_const( false );
    537                                 impCpCtorExpr->returnDecls.push_back( ret );
     623                                returnDecl = ret;
     624                                stmtsToAddBefore.push_back( new DeclStmt( ret ) );
    538625                                CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
     626                        } // for
     627                        CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
     628                        // ------------------------------------------------------
     629
     630                        CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
     631
     632                        // detach fields from wrapper node so that it can be deleted without deleting too much
     633                        impCpCtorExpr->callExpr = nullptr;
     634                        std::swap( impCpCtorExpr->env, appExpr->env );
     635                        assert( impCpCtorExpr->env == nullptr );
     636                        delete impCpCtorExpr;
     637
     638                        if ( returnDecl ) {
     639                                Expression * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), appExpr );
    539640                                if ( ! dynamic_cast< ReferenceType * >( result ) ) {
    540641                                        // destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
    541                                         destructRet( ret, impCpCtorExpr );
    542                                 }
     642                                        destructRet( returnDecl, impCpCtorExpr, assign );
     643                                } else {
     644                                        assign = new CommaExpr( assign, new VariableExpr( returnDecl ) );
     645                                }
     646                                // move env from appExpr to retExpr
     647                                std::swap( assign->env, appExpr->env );
     648                                return assign;
     649                        } else {
     650                                return appExpr;
     651                        } // if
     652                }
     653
     654                void ResolveCopyCtors::premutate( StmtExpr * stmtExpr ) {
     655                        // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
     656                        // since temporaries can be shared across sub-expressions, e.g.
     657                        //   [A, A] f();
     658                        //   g([A] x, [A] y);
     659                        //   g(f());
     660                        // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
     661                        // Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added
     662                        // to the outer context, rather than inside of the statement expression.
     663                        visit_children = false;
     664
     665                        assert( env );
     666
     667                        // visit all statements
     668                        std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
     669                        for ( Statement *& stmt : stmts ) {
     670                                stmt = stmt->acceptMutator( *visitor );
    543671                        } // for
    544                         CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
    545                 }
    546 
    547                 void ResolveCopyCtors::postvisit( StmtExpr * stmtExpr ) {
    548                         assert( env );
    549                         assert( stmtExpr->get_result() );
    550                         Type * result = stmtExpr->get_result();
     672
     673                        assert( stmtExpr->result );
     674                        Type * result = stmtExpr->result;
    551675                        if ( ! result->isVoid() ) {
    552676                                static UniqueName retNamer("_tmp_stmtexpr_ret");
     
    562686                                ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
    563687                                ret->type->set_const( false );
    564                                 stmtExpr->returnDecls.push_front( ret );
     688                                stmtsToAddBefore.push_back( new DeclStmt( ret ) );
    565689
    566690                                // must have a non-empty body, otherwise it wouldn't have a result
    567691                                CompoundStmt * body = stmtExpr->statements;
    568                                 assert( ! body->get_kids().empty() );
     692                                assert( ! body->kids.empty() );
    569693                                // must be an ExprStmt, otherwise it wouldn't have a result
    570                                 ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->get_kids().back() );
    571                                 last->expr = makeCtorDtor( "?{}", ret, last->get_expr() );
    572 
    573                                 stmtExpr->dtors.push_front( makeCtorDtor( "^?{}", ret ) );
     694                                ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->kids.back() );
     695                                last->expr = makeCtorDtor( "?{}", ret, last->expr );
     696
     697                                // add destructors after current statement
     698                                stmtsToAddAfter.push_back( new ExprStmt( makeCtorDtor( "^?{}", ret ) ) );
     699
     700                                // must have a non-empty body, otherwise it wouldn't have a result
     701                                assert( ! stmts.empty() );
     702
     703                                // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
     704                                stmts.push_back( new ExprStmt( new VariableExpr( ret ) ) );
    574705                        } // if
    575                 }
    576 
    577                 void ResolveCopyCtors::previsit( UniqueExpr * unqExpr ) {
    578                         unqCount[ unqExpr->get_id() ]++;  // count the number of unique expressions for each ID
    579                         if ( vars.count( unqExpr->get_id() ) ) {
    580                                 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
    581                                 visit_children = false;
    582                         }
     706
     707                        assert( stmtExpr->returnDecls.empty() );
     708                        assert( stmtExpr->dtors.empty() );
    583709                }
    584710
     
    597723                }
    598724
    599                 void ResolveCopyCtors::postvisit( UniqueExpr * unqExpr ) {
    600                         if ( vars.count( unqExpr->get_id() ) ) {
    601                                 // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
    602                                 return;
    603                         }
    604 
    605                         // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
    606                         assert( unqExpr->get_result() );
    607                         if ( ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast<ImplicitCopyCtorExpr*>( unqExpr->get_expr() ) ) {
    608                                 // note the variable used as the result from the call
    609                                 assert( impCpCtorExpr->get_result() && impCpCtorExpr->get_returnDecls().size() == 1 );
    610                                 unqExpr->set_var( new VariableExpr( impCpCtorExpr->get_returnDecls().front() ) );
     725                void ResolveCopyCtors::premutate( UniqueExpr * unqExpr ) {
     726                        visit_children = false;
     727                        // xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
     728                        static std::unordered_map< int, UniqueExpr * > unqMap;
     729                        if ( ! unqMap.count( unqExpr->get_id() ) ) {
     730                                // resolve expr and find its
     731
     732                                ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( unqExpr->expr );
     733                                // PassVisitor<ResolveCopyCtors> fixer;
     734                                unqExpr->expr = unqExpr->expr->acceptMutator( *visitor );
     735
     736                                // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
     737                                assert( unqExpr->result );
     738                                if ( impCpCtorExpr ) {
     739                                        CommaExpr * comma = strict_dynamic_cast< CommaExpr * >( unqExpr->expr );
     740                                        VariableExpr * var = strict_dynamic_cast<VariableExpr *>( comma->arg2 );
     741                                        // note the variable used as the result from the call
     742                                        unqExpr->var = var->clone();
     743                                } else {
     744                                        // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
     745                                        unqExpr->object = ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->result->clone(), makeInit( unqExpr->result ) );
     746                                        unqExpr->var = new VariableExpr( unqExpr->object );
     747                                }
     748
     749                                // stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
     750                                // stmtsToAddAfter.splice( stmtsToAddAfter.end(), fixer.pass.stmtsToAddAfter );
     751                                unqMap[unqExpr->get_id()] = unqExpr;
    611752                        } else {
    612                                 // expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
    613                                 unqExpr->set_object( ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->get_result()->clone(), makeInit( unqExpr->get_result() ) ) );
    614                                 unqExpr->set_var( new VariableExpr( unqExpr->get_object() ) );
    615                         }
    616                         vars.insert( unqExpr->get_id() );
    617                 }
    618 
    619                 Expression * FixCopyCtors::postmutate( ImplicitCopyCtorExpr * impCpCtorExpr ) {
    620                         CP_CTOR_PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; )
    621 
    622                         std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls();
    623                         std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls();
    624                         std::list< Expression * > & dtors = impCpCtorExpr->get_dtors();
    625 
    626                         // add all temporary declarations and their constructors
    627                         for ( ObjectDecl * obj : tempDecls ) {
    628                                 stmtsToAddBefore.push_back( new DeclStmt( obj ) );
    629                         } // for
    630                         for ( ObjectDecl * obj : returnDecls ) {
    631                                 stmtsToAddBefore.push_back( new DeclStmt( obj ) );
    632                         } // for
    633 
    634                         // add destructors after current statement
    635                         for ( Expression * dtor : dtors ) {
    636                                 // take relevant bindings from environment
    637                                 assert( ! dtor->env );
    638                                 dtor->env =  maybeClone( env );
    639                                 stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
    640                         } // for
    641 
    642                         ObjectDecl * returnDecl = returnDecls.empty() ? nullptr : returnDecls.front();
    643                         Expression * callExpr = impCpCtorExpr->get_callExpr();
    644 
    645                         CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
    646 
    647                         // detach fields from wrapper node so that it can be deleted without deleting too much
    648                         dtors.clear();
    649                         tempDecls.clear();
    650                         returnDecls.clear();
    651                         impCpCtorExpr->set_callExpr( nullptr );
    652                         std::swap( impCpCtorExpr->env, callExpr->env );
    653                         assert( impCpCtorExpr->env == nullptr );
    654                         delete impCpCtorExpr;
    655 
    656                         if ( returnDecl ) {
    657                                 ApplicationExpr * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), callExpr );
    658                                 Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) );
    659                                 // move env from callExpr to retExpr
    660                                 std::swap( retExpr->env, callExpr->env );
    661                                 return retExpr;
    662                         } else {
    663                                 return callExpr;
    664                         } // if
    665                 }
    666 
    667                 void FixCopyCtors::premutate( StmtExpr * stmtExpr ) {
    668                         // function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
    669                         // since temporaries can be shared across sub-expressions, e.g.
    670                         //   [A, A] f();
    671                         //   g([A] x, [A] y);
    672                         //   g(f());
    673                         // f is executed once, so the return temporary is shared across the tuple constructors for x and y.
    674                         // Explicitly mutating children instead of mutating the inner compound statment forces the temporaries to be added
    675                         // to the outer context, rather than inside of the statement expression.
    676                         visit_children = false;
    677                         std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
    678                         for ( Statement *& stmt : stmts ) {
    679                                 stmt = stmt->acceptMutator( *visitor );
    680                         } // for
    681                         assert( stmtExpr->result );
    682                         Type * result = stmtExpr->result;
    683                         if ( ! result->isVoid() ) {
    684                                 for ( ObjectDecl * obj : stmtExpr->returnDecls ) {
    685                                         stmtsToAddBefore.push_back( new DeclStmt( obj ) );
    686                                 } // for
    687                                 // add destructors after current statement
    688                                 for ( Expression * dtor : stmtExpr->dtors ) {
    689                                         stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
    690                                 } // for
    691                                 // must have a non-empty body, otherwise it wouldn't have a result
    692                                 assert( ! stmts.empty() );
    693                                 assertf( ! stmtExpr->returnDecls.empty() || stmtExpr->dtors.empty(), "StmtExpr returns non-void, but no return decls: %s", toString( stmtExpr ).c_str() );
    694                                 // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
    695                                 if ( ! stmtExpr->returnDecls.empty() ) {
    696                                         stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->returnDecls.front() ) ) );
    697                                 }
    698                                 stmtExpr->returnDecls.clear();
    699                                 stmtExpr->dtors.clear();
    700                         }
    701                         assert( stmtExpr->returnDecls.empty() );
    702                         assert( stmtExpr->dtors.empty() );
    703                 }
    704 
    705                 void FixCopyCtors::premutate( UniqueExpr * unqExpr ) {
    706                         visit_children = false;
    707                         unqCount[ unqExpr->get_id() ]--;
    708                         static std::unordered_map< int, std::list< Statement * > > dtors;
    709                         static std::unordered_map< int, UniqueExpr * > unqMap;
    710                         // has to be done to clean up ImplicitCopyCtorExpr nodes, even when this node was skipped in previous passes
    711                         if ( unqMap.count( unqExpr->get_id() ) ) {
    712753                                // take data from other UniqueExpr to ensure consistency
    713754                                delete unqExpr->get_expr();
    714                                 unqExpr->set_expr( unqMap[unqExpr->get_id()]->get_expr()->clone() );
    715                                 delete unqExpr->get_result();
    716                                 unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) );
    717                                 if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
    718                                         stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
    719                                 }
    720                                 return;
    721                         }
    722                         PassVisitor<FixCopyCtors> fixer( unqCount );
    723                         unqExpr->set_expr( unqExpr->get_expr()->acceptMutator( fixer ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
    724                         stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
    725                         unqMap[unqExpr->get_id()] = unqExpr;
    726                         if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
    727                                 stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
    728                         } else { // remember dtors for last instance of unique expr
    729                                 dtors[ unqExpr->get_id() ] = fixer.pass.stmtsToAddAfter;
    730                         }
    731                         return;
     755                                unqExpr->expr = unqMap[unqExpr->get_id()]->expr->clone();
     756                                delete unqExpr->result;
     757                                unqExpr->result = maybeClone( unqExpr->expr->result );
     758                        }
    732759                }
    733760
     
    844871                                                        ctorInit->ctor = nullptr;
    845872                                                }
     873
     874                                                Statement * dtor = ctorInit->dtor;
     875                                                if ( dtor ) {
     876                                                        ImplicitCtorDtorStmt * implicit = strict_dynamic_cast< ImplicitCtorDtorStmt * >( dtor );
     877                                                        Statement * dtorStmt = implicit->callStmt;
     878
     879                                                        // don't need to call intrinsic dtor, because it does nothing, but
     880                                                        // non-intrinsic dtors must be called
     881                                                        if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
     882                                                                // set dtor location to the object's location for error messages
     883                                                                DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
     884                                                                objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
     885                                                                ctorInit->dtor = nullptr;
     886                                                        } // if
     887                                                }
    846888                                        } // if
    847889                                } else if ( Initializer * init = ctorInit->init ) {
     
    886928
    887929
    888                 template<typename Iterator, typename OutputIterator>
    889                 void insertDtors( Iterator begin, Iterator end, OutputIterator out ) {
    890                         for ( Iterator it = begin ; it != end ; ++it ) {
    891                                 // extract destructor statement from the object decl and insert it into the output. Note that this is
    892                                 // only called on lists of non-static objects with implicit non-intrinsic dtors, so if the user manually
    893                                 // calls an intrinsic dtor then the call must (and will) still be generated since the argument may
    894                                 // contain side effects.
    895                                 ObjectDecl * objDecl = *it;
    896                                 ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() );
    897                                 assert( ctorInit && ctorInit->get_dtor() );
    898                                 *out++ = ctorInit->get_dtor()->clone();
    899                         } // for
    900                 }
    901 
    902                 void InsertDtors::previsit( ObjectDecl * objDecl ) {
    903                         // remember non-static destructed objects so that their destructors can be inserted later
    904                         if ( ! objDecl->get_storageClasses().is_static ) {
    905                                 if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
    906                                         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    907                                         assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
    908                                         Statement * dtor = ctorInit->get_dtor();
    909                                         // don't need to call intrinsic dtor, because it does nothing, but
    910                                         // non-intrinsic dtors must be called
    911                                         if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    912                                                 // set dtor location to the object's location for error messages
    913                                                 ctorInit->dtor->location = objDecl->location;
    914                                                 reverseDeclOrder.front().push_front( objDecl );
    915                                         } // if
    916                                 } // if
    917                         } // if
    918                 }
    919 
    920930                void InsertDtors::previsit( FunctionDecl * funcDecl ) {
    921931                        // each function needs to have its own set of labels
     
    930940                }
    931941
    932                 void InsertDtors::previsit( CompoundStmt * compoundStmt ) {
    933                         // visit statements - this will also populate reverseDeclOrder list.  don't want to dump all destructors
    934                         // when block is left, just the destructors associated with variables defined in this block, so push a new
    935                         // list to the top of the stack so that we can differentiate scopes
    936                         reverseDeclOrder.push_front( OrderedDecls() );
    937                         Parent::previsit( compoundStmt );
    938                 }
    939 
    940                 void InsertDtors::postvisit( CompoundStmt * compoundStmt ) {
    941                         // add destructors for the current scope that we're exiting, unless the last statement is a return, which
    942                         // causes unreachable code warnings
    943                         std::list< Statement * > & statements = compoundStmt->get_kids();
    944                         if ( ! statements.empty() && ! dynamic_cast< ReturnStmt * >( statements.back() ) ) {
    945                                 insertDtors( reverseDeclOrder.front().begin(), reverseDeclOrder.front().end(), back_inserter( statements ) );
    946                         }
    947                         reverseDeclOrder.pop_front();
    948                 }
    949 
    950                 void InsertDtors::previsit( ReturnStmt * ) {
    951                         // return exits all scopes, so dump destructors for all scopes
    952                         for ( OrderedDecls & od : reverseDeclOrder ) {
    953                                 insertDtors( od.begin(), od.end(), back_inserter( stmtsToAddBefore ) );
    954                         } // for
    955                 }
    956 
    957942                // Handle break/continue/goto in the same manner as C++.  Basic idea: any objects that are in scope at the
    958943                // BranchStmt but not at the labelled (target) statement must be destructed.  If there are any objects in scope
     
    982967                        if ( ! diff.empty() ) {
    983968                                SemanticError( stmt, std::string("jump to label '") + stmt->get_target().get_name() + "' crosses initialization of " + (*diff.begin())->get_name() + " " );
    984                         } // if
    985                         // S_G-S_L results in set of objects that must be destructed
    986                         diff.clear();
    987                         std::set_difference( curVars.begin(), curVars.end(), lvars.begin(), lvars.end(), std::inserter( diff, diff.end() ) );
    988                         DTOR_PRINT(
    989                                 std::cerr << "S_G-S_L = " << printSet( diff ) << std::endl;
    990                         )
    991                         if ( ! diff.empty() ) {
    992                                 // create an auxilliary set for fast lookup -- can't make diff a set, because diff ordering should be consistent for error messages.
    993                                 std::unordered_set<ObjectDecl *> needsDestructor( diff.begin(), diff.end() );
    994 
    995                                 // go through decl ordered list of objectdecl. for each element that occurs in diff, output destructor
    996                                 OrderedDecls ordered;
    997                                 for ( OrderedDecls & rdo : reverseDeclOrder ) {
    998                                         // add elements from reverseDeclOrder into ordered if they occur in diff - it is key that this happens in reverse declaration order.
    999                                         copy_if( rdo.begin(), rdo.end(), back_inserter( ordered ), [&]( ObjectDecl * objDecl ) { return needsDestructor.count( objDecl ); } );
    1000                                 } // for
    1001                                 insertDtors( ordered.begin(), ordered.end(), back_inserter( stmtsToAddBefore ) );
    1002969                        } // if
    1003970                }
     
    11161083                                                        callStmt->acceptMutator( *visitor );
    11171084                                                        if ( isCtor ) {
    1118                                                                 function->get_statements()->push_front( callStmt );
    1119                                                         } else {
     1085                                                                function->statements->push_front( callStmt );
     1086                                                        } else { // TODO: don't generate destructor function/object for intrinsic calls
    11201087                                                                // destructor statements should be added at the end
    1121                                                                 function->get_statements()->push_back( callStmt );
     1088                                                                // function->get_statements()->push_back( callStmt );
     1089
     1090                                                                // Optimization: do not need to call intrinsic destructors on members
     1091                                                                if ( isIntrinsicSingleArgCallStmt( callStmt ) ) continue;;
     1092
     1093                                                                // __Destructor _dtor0 = { (void *)&b.a1, (void (*)(void *)_destroy_A };
     1094                                                                std::list< Statement * > stmtsToAdd;
     1095
     1096                                                                static UniqueName memberDtorNamer = { "__memberDtor" };
     1097                                                                assertf( Validate::dtorStruct, "builtin __Destructor not found." );
     1098                                                                assertf( Validate::dtorStructDestroy, "builtin __destroy_Destructor not found." );
     1099
     1100                                                                Expression * thisExpr = new CastExpr( new AddressExpr( new VariableExpr( thisParam ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
     1101                                                                Expression * dtorExpr = new VariableExpr( getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
     1102
     1103                                                                // cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
     1104                                                                FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
     1105                                                                dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
     1106                                                                Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
     1107
     1108                                                                ObjectDecl * destructor = ObjectDecl::newObject( memberDtorNamer.newName(), new StructInstType( Type::Qualifiers(), Validate::dtorStruct ), new ListInit( { new SingleInit( thisExpr ), new SingleInit( new CastExpr( dtorExpr, dtorType ) ) } ) );
     1109                                                                function->statements->push_front( new DeclStmt( destructor ) );
     1110                                                                destructor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
     1111
     1112                                                                function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
    11221113                                                        }
    11231114                                                } catch ( SemanticErrorException & error ) {
  • src/InitTweak/GenInit.cc

    rc786e1d r6054b18  
    1515#include "GenInit.h"
    1616
    17 #include <stddef.h>                // for NULL
    18 #include <algorithm>               // for any_of
    19 #include <cassert>                 // for assert, strict_dynamic_cast, assertf
    20 #include <iterator>                // for back_inserter, inserter, back_inse...
    21 #include <list>                    // for _List_iterator, list
     17#include <stddef.h>                    // for NULL
     18#include <algorithm>                   // for any_of
     19#include <cassert>                     // for assert, strict_dynamic_cast, assertf
     20#include <iterator>                    // for back_inserter, inserter, back_inse...
     21#include <list>                        // for _List_iterator, list
    2222
    2323#include "CodeGen/OperatorTable.h"
    24 #include "Common/PassVisitor.h"    // for PassVisitor, WithGuards, WithShort...
    25 #include "Common/SemanticError.h"  // for SemanticError
    26 #include "Common/UniqueName.h"     // for UniqueName
    27 #include "Common/utility.h"        // for ValueGuard, maybeClone
    28 #include "GenPoly/GenPoly.h"       // for getFunctionType, isPolyType
    29 #include "GenPoly/ScopedSet.h"     // for ScopedSet, ScopedSet<>::const_iter...
    30 #include "InitTweak.h"             // for isConstExpr, InitExpander, checkIn...
    31 #include "Parser/LinkageSpec.h"    // for isOverridable, C
     24#include "Common/PassVisitor.h"        // for PassVisitor, WithGuards, WithShort...
     25#include "Common/SemanticError.h"      // for SemanticError
     26#include "Common/UniqueName.h"         // for UniqueName
     27#include "Common/utility.h"            // for ValueGuard, maybeClone
     28#include "GenPoly/GenPoly.h"           // for getFunctionType, isPolyType
     29#include "GenPoly/ScopedSet.h"         // for ScopedSet, ScopedSet<>::const_iter...
     30#include "InitTweak.h"                 // for isConstExpr, InitExpander, checkIn...
     31#include "Parser/LinkageSpec.h"        // for isOverridable, C
    3232#include "ResolvExpr/Resolver.h"
    33 #include "SymTab/Autogen.h"        // for genImplicitCall, SizeType
    34 #include "SymTab/Mangler.h"        // for Mangler
    35 #include "SynTree/Declaration.h"   // for ObjectDecl, DeclarationWithType
    36 #include "SynTree/Expression.h"    // for VariableExpr, UntypedExpr, Address...
    37 #include "SynTree/Initializer.h"   // for ConstructorInit, SingleInit, Initi...
    38 #include "SynTree/Label.h"         // for Label
    39 #include "SynTree/Mutator.h"       // for mutateAll
    40 #include "SynTree/Statement.h"     // for CompoundStmt, ImplicitCtorDtorStmt
    41 #include "SynTree/Type.h"          // for Type, ArrayType, Type::Qualifiers
    42 #include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
    43 #include "Tuples/Tuples.h"         // for maybeImpure
     33#include "SymTab/Autogen.h"            // for genImplicitCall
     34#include "SymTab/Mangler.h"            // for Mangler
     35#include "SynTree/Declaration.h"       // for ObjectDecl, DeclarationWithType
     36#include "SynTree/Expression.h"        // for VariableExpr, UntypedExpr, Address...
     37#include "SynTree/Initializer.h"       // for ConstructorInit, SingleInit, Initi...
     38#include "SynTree/Label.h"             // for Label
     39#include "SynTree/Mutator.h"           // for mutateAll
     40#include "SynTree/Statement.h"         // for CompoundStmt, ImplicitCtorDtorStmt
     41#include "SynTree/Type.h"              // for Type, ArrayType, Type::Qualifiers
     42#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
     43#include "Tuples/Tuples.h"             // for maybeImpure
     44#include "Validate/FindSpecialDecls.h" // for SizeType
    4445
    4546namespace InitTweak {
     
    186187
    187188                        // need to resolve array dimensions in order to accurately determine if constexpr
    188                         ResolvExpr::findSingleExpression( arrayType->dimension, SymTab::SizeType->clone(), indexer );
     189                        ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
    189190                        // array is variable-length when the dimension is not constexpr
    190191                        arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
     
    192193                        if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
    193194
    194                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, SymTab::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
     195                        ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    195196                        arrayDimension->get_type()->set_const( true );
    196197
  • src/InitTweak/InitTweak.cc

    rc786e1d r6054b18  
    340340                std::list< Expression * > matches;
    341341                collectCtorDtorCalls( stmt, matches );
    342                 assert( matches.size() <= 1 );
     342                assertf( matches.size() <= 1, "%zd constructor/destructors found in %s", matches.size(), toString( stmt ).c_str() );
    343343                return matches.size() == 1 ? matches.front() : nullptr;
    344344        }
  • src/Makefile.am

    rc786e1d r6054b18  
    7070ARFLAGS     = cr
    7171
    72 demangler_SOURCES = SymTab/demangler.cc
     72demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete
    7373
    7474demangler_LDADD = libdemangle.a -ldl                    # yywrap
  • src/Makefile.in

    rc786e1d r6054b18  
    234234        $(am__objects_7) Tuples/TupleAssignment.$(OBJEXT) \
    235235        Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
    236         Validate/HandleAttributes.$(OBJEXT)
     236        Validate/HandleAttributes.$(OBJEXT) \
     237        Validate/FindSpecialDecls.$(OBJEXT)
    237238am_libdemangle_a_OBJECTS = $(am__objects_8)
    238239libdemangle_a_OBJECTS = $(am_libdemangle_a_OBJECTS)
     
    265266        Tuples/TupleExpansion.$(OBJEXT) Tuples/Explode.$(OBJEXT) \
    266267        Validate/HandleAttributes.$(OBJEXT) \
     268        Validate/FindSpecialDecls.$(OBJEXT) \
    267269        Virtual/ExpandCasts.$(OBJEXT)
    268270am____driver_cfa_cpp_OBJECTS = $(am__objects_9)
     
    555557        $(SRC_SYMTAB) $(SRC_SYNTREE) Tuples/TupleAssignment.cc \
    556558        Tuples/TupleExpansion.cc Tuples/Explode.cc \
    557         Validate/HandleAttributes.cc Virtual/ExpandCasts.cc
     559        Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc \
     560        Virtual/ExpandCasts.cc
    558561SRCDEMANGLE = CompilationState.cc $(SRC_AST) $(SRC_CODEGEN) \
    559562        Concurrency/Keywords.cc $(SRC_COMMON) $(SRC_CONTROLSTRUCT) \
     
    562565        $(SRC_SYMTAB) SymTab/Demangle.cc $(SRC_SYNTREE) \
    563566        Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
    564         Tuples/Explode.cc Validate/HandleAttributes.cc
     567        Tuples/Explode.cc Validate/HandleAttributes.cc \
     568        Validate/FindSpecialDecls.cc
    565569MAINTAINERCLEANFILES = ${libdir}/${notdir ${cfa_cpplib_PROGRAMS}}
    566570MOSTLYCLEANFILES = Parser/lex.cc Parser/parser.cc Parser/parser.hh \
     
    685689AM_LDFLAGS = @HOST_FLAGS@ -Xlinker -export-dynamic
    686690ARFLAGS = cr
    687 demangler_SOURCES = SymTab/demangler.cc
     691demangler_SOURCES = SymTab/demangler.cc # test driver for the demangler, also useful as a sanity check that libdemangle.a is complete
    688692demangler_LDADD = libdemangle.a -ldl                    # yywrap
    689693noinst_LIBRARIES = libdemangle.a
     
    10081012        @: > Validate/$(DEPDIR)/$(am__dirstamp)
    10091013Validate/HandleAttributes.$(OBJEXT): Validate/$(am__dirstamp) \
     1014        Validate/$(DEPDIR)/$(am__dirstamp)
     1015Validate/FindSpecialDecls.$(OBJEXT): Validate/$(am__dirstamp) \
    10101016        Validate/$(DEPDIR)/$(am__dirstamp)
    10111017
     
    13011307@AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/TupleAssignment.Po@am__quote@
    13021308@AMDEP_TRUE@@am__include@ @am__quote@Tuples/$(DEPDIR)/TupleExpansion.Po@am__quote@
     1309@AMDEP_TRUE@@am__include@ @am__quote@Validate/$(DEPDIR)/FindSpecialDecls.Po@am__quote@
    13031310@AMDEP_TRUE@@am__include@ @am__quote@Validate/$(DEPDIR)/HandleAttributes.Po@am__quote@
    13041311@AMDEP_TRUE@@am__include@ @am__quote@Virtual/$(DEPDIR)/ExpandCasts.Po@am__quote@
  • src/Parser/parser.yy

    rc786e1d r6054b18  
    13581358
    13591359handler_clause:
    1360         handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement pop
     1360        handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    13611361                { $$ = new StatementNode( build_catch( $1, $4, $6, $8 ) ); }
    1362         | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement pop
     1362        | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    13631363                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $2, $5, $7, $9 ) ) ); }
    13641364        ;
  • src/ResolvExpr/Resolver.cc

    rc786e1d r6054b18  
    4343#include "typeops.h"                     // for extractResultType
    4444#include "Unify.h"                       // for unify
     45#include "Validate/FindSpecialDecls.h"   // for SizeType
    4546
    4647using namespace std;
     
    235236                                winner.cost = winner.cvtCost;
    236237                        }
    237                        
     238
    238239                        // produce ambiguous errors, if applicable
    239240                        if ( winners.size() != 1 ) {
     
    255256
    256257                        // xxx - check for ambiguous expressions
    257                        
     258
    258259                        // output selected choice
    259260                        alt = std::move( choice );
     
    402403
    403404        void Resolver::previsit( ObjectDecl * objectDecl ) {
    404                 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that 
    405                 // class-variable initContext is changed multiple time because the LHS is analysed twice. 
    406                 // The second analysis changes initContext because of a function type can contain object 
    407                 // declarations in the return and parameter types. So each value of initContext is 
     405                // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that
     406                // class-variable initContext is changed multiple time because the LHS is analysed twice.
     407                // The second analysis changes initContext because of a function type can contain object
     408                // declarations in the return and parameter types. So each value of initContext is
    408409                // retained, so the type on the first analysis is preserved and used for selecting the RHS.
    409410                GuardValue( currentObject );
     
    419420        void Resolver::handlePtrType( PtrType * type ) {
    420421                if ( type->get_dimension() ) {
    421                         findSingleExpression( type->dimension, SymTab::SizeType->clone(), indexer );
     422                        findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
    422423                }
    423424        }
     
    442443
    443444        void Resolver::postvisit( FunctionDecl * functionDecl ) {
    444                 // default value expressions have an environment which shouldn't be there and trips up 
     445                // default value expressions have an environment which shouldn't be there and trips up
    445446                // later passes.
    446                 // xxx - it might be necessary to somehow keep the information from this environment, but I 
     447                // xxx - it might be necessary to somehow keep the information from this environment, but I
    447448                // can't currently see how it's useful.
    448449                for ( Declaration * d : functionDecl->type->parameters ) {
     
    795796                initExpr->expr = nullptr;
    796797                std::swap( initExpr->env, newExpr->env );
    797                 // InitExpr may have inferParams in the case where the expression specializes a function 
    798                 // pointer, and newExpr may already have inferParams of its own, so a simple swap is not 
     798                // InitExpr may have inferParams in the case where the expression specializes a function
     799                // pointer, and newExpr may already have inferParams of its own, so a simple swap is not
    799800                // sufficient.
    800801                newExpr->spliceInferParams( initExpr );
    801802                delete initExpr;
    802803
    803                 // get the actual object's type (may not exactly match what comes back from the resolver 
     804                // get the actual object's type (may not exactly match what comes back from the resolver
    804805                // due to conversions)
    805806                Type * initContext = currentObject.getCurrentType();
     
    814815                                        if ( isCharType( pt->get_base() ) ) {
    815816                                                if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {
    816                                                         // strip cast if we're initializing a char[] with a char *, 
     817                                                        // strip cast if we're initializing a char[] with a char *,
    817818                                                        // e.g.  char x[] = "hello";
    818819                                                        newExpr = ce->get_arg();
     
    837838                // move cursor into brace-enclosed initializer-list
    838839                currentObject.enterListInit();
    839                 // xxx - fix this so that the list isn't copied, iterator should be used to change current 
     840                // xxx - fix this so that the list isn't copied, iterator should be used to change current
    840841                // element
    841842                std::list<Designation *> newDesignations;
    842843                for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {
    843                         // iterate designations and initializers in pairs, moving the cursor to the current 
     844                        // iterate designations and initializers in pairs, moving the cursor to the current
    844845                        // designated object and resolving the initializer against that object.
    845846                        Designation * des = std::get<0>(p);
  • src/SymTab/Autogen.cc

    rc786e1d r6054b18  
    4141
    4242namespace SymTab {
    43         Type * SizeType = 0;
    44 
    4543        /// Data used to generate functions generically. Specifically, the name of the generated function and a function which generates the routine protoype
    4644        struct FuncData {
    47                 typedef FunctionType * (*TypeGen)( Type * );
     45                typedef FunctionType * (*TypeGen)( Type *, bool );
    4846                FuncData( const std::string & fname, const TypeGen & genType ) : fname( fname ), genType( genType ) {}
    4947                std::string fname;
     
    231229
    232230        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    233         FunctionType * genDefaultType( Type * paramType ) {
    234                 const auto & typeParams = getGenericParams( paramType );
     231        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
    235232                FunctionType *ftype = new FunctionType( Type::Qualifiers(), false );
    236                 cloneAll( typeParams, ftype->forall );
     233                if ( maybePolymorphic ) {
     234                        // only copy in
     235                        const auto & typeParams = getGenericParams( paramType );
     236                        cloneAll( typeParams, ftype->forall );
     237                }
    237238                ObjectDecl *dstParam = new ObjectDecl( "_dst", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), paramType->clone() ), nullptr );
    238239                ftype->parameters.push_back( dstParam );
     
    241242
    242243        /// given type T, generate type of copy ctor, i.e. function type void (*) (T *, T)
    243         FunctionType * genCopyType( Type * paramType ) {
    244                 FunctionType *ftype = genDefaultType( paramType );
     244        FunctionType * genCopyType( Type * paramType, bool maybePolymorphic ) {
     245                FunctionType *ftype = genDefaultType( paramType, maybePolymorphic );
    245246                ObjectDecl *srcParam = new ObjectDecl( "_src", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr );
    246247                ftype->parameters.push_back( srcParam );
     
    249250
    250251        /// given type T, generate type of assignment, i.e. function type T (*) (T *, T)
    251         FunctionType * genAssignType( Type * paramType ) {
    252                 FunctionType *ftype = genCopyType( paramType );
     252        FunctionType * genAssignType( Type * paramType, bool maybePolymorphic ) {
     253                FunctionType *ftype = genCopyType( paramType, maybePolymorphic );
    253254                ObjectDecl *returnVal = new ObjectDecl( "_ret", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr );
    254255                ftype->returnVals.push_back( returnVal );
     
    308309                for ( const FuncData & d : data ) {
    309310                        // generate a function (?{}, ?=?, ^?{}) based on the current FuncData.
    310                         FunctionType * ftype = d.genType( type );
     311                        FunctionType * ftype = d.genType( type, true );
    311312
    312313                        // destructor for concurrent type must be mutex
  • src/SymTab/Autogen.h

    rc786e1d r6054b18  
    3737        bool isUnnamedBitfield( ObjectDecl * obj );
    3838
    39         /// size_t type - set when size_t typedef is seen. Useful in a few places,
    40         /// such as in determining array dimension type
    41         extern Type * SizeType;
    42 
    43         /// intrinsic dereference operator for unqualified types - set when *? function is seen in FindSpecialDeclarations.
    44         /// Useful for creating dereference ApplicationExprs without a full resolver pass.
    45         extern FunctionDecl * dereferenceOperator;
    46 
    47         // generate the type of an assignment function for paramType
    48         FunctionType * genAssignType( Type * paramType );
    49 
    50         // generate the type of a default constructor or destructor for paramType
    51         FunctionType * genDefaultType( Type * paramType );
    52 
    53         // generate the type of a copy constructor for paramType
    54         FunctionType * genCopyType( Type * paramType );
     39        /// generate the type of an assignment function for paramType.
     40        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
     41        FunctionType * genAssignType( Type * paramType, bool maybePolymorphic = true );
     42
     43        /// generate the type of a default constructor or destructor for paramType.
     44        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
     45        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
     46
     47        /// generate the type of a copy constructor for paramType.
     48        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
     49        FunctionType * genCopyType( Type * paramType, bool maybePolymorphic = true );
    5550
    5651        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
  • src/SymTab/Validate.cc

    rc786e1d r6054b18  
    7676#include "SynTree/Visitor.h"           // for Visitor
    7777#include "Validate/HandleAttributes.h" // for handleAttributes
     78#include "Validate/FindSpecialDecls.h" // for FindSpecialDecls
    7879
    7980class CompoundStmt;
     
    288289        };
    289290
    290         FunctionDecl * dereferenceOperator = nullptr;
    291         struct FindSpecialDeclarations final {
    292                 void previsit( FunctionDecl * funcDecl );
    293         };
    294 
    295291        void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) {
    296292                PassVisitor<EnumAndPointerDecay> epc;
     
    299295                PassVisitor<CompoundLiteral> compoundliteral;
    300296                PassVisitor<ValidateGenericParameters> genericParams;
    301                 PassVisitor<FindSpecialDeclarations> finder;
    302297                PassVisitor<LabelAddressFixer> labelAddrFixer;
    303298                PassVisitor<HoistTypeDecls> hoistDecls;
     
    378373                        });
    379374                        Stats::Time::TimeBlock("Find Special Declarations", [&]() {
    380                                 acceptAll( translationUnit, finder ); // xxx - remove this pass soon
     375                                Validate::findSpecialDecls( translationUnit );
    381376                        });
    382377                        Stats::Time::TimeBlock("Fix Label Address", [&]() {
     
    943938                if ( eliminator.pass.typedefNames.count( "size_t" ) ) {
    944939                        // grab and remember declaration of size_t
    945                         SizeType = eliminator.pass.typedefNames["size_t"].first->base->clone();
     940                        Validate::SizeType = eliminator.pass.typedefNames["size_t"].first->base->clone();
    946941                } else {
    947942                        // xxx - missing global typedef for size_t - default to long unsigned int, even though that may be wrong
    948943                        // eventually should have a warning for this case.
    949                         SizeType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
     944                        Validate::SizeType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
    950945                }
    951946        }
     
    13351330                        // need to resolve array dimensions early so that constructor code can correctly determine
    13361331                        // if a type is a VLA (and hence whether its elements need to be constructed)
    1337                         ResolvExpr::findSingleExpression( type->dimension, SymTab::SizeType->clone(), indexer );
     1332                        ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
    13381333
    13391334                        // must re-evaluate whether a type is a VLA, now that more information is available
     
    13721367                return addrExpr;
    13731368        }
    1374 
    1375         void FindSpecialDeclarations::previsit( FunctionDecl * funcDecl ) {
    1376                 if ( ! dereferenceOperator ) {
    1377                         if ( funcDecl->get_name() == "*?" && funcDecl->get_linkage() == LinkageSpec::Intrinsic ) {
    1378                                 FunctionType * ftype = funcDecl->get_functionType();
    1379                                 if ( ftype->get_parameters().size() == 1 && ftype->get_parameters().front()->get_type()->get_qualifiers() == Type::Qualifiers() ) {
    1380                                         dereferenceOperator = funcDecl;
    1381                                 }
    1382                         }
    1383                 }
    1384         }
    13851369} // namespace SymTab
    13861370
  • src/SynTree/DeclReplacer.cc

    rc786e1d r6054b18  
    3838                        void previsit( TypeInstType * inst );
    3939                };
     40
     41                /// Mutator that replaces uses of declarations with arbitrary expressions, according to the supplied mapping
     42                struct ExprDeclReplacer {
     43                private:
     44                        const ExprMap & exprMap;
     45                        bool debug;
     46                public:
     47                        ExprDeclReplacer( const ExprMap & exprMap, bool debug = false );
     48
     49                        // replace variable with new node from expr map
     50                        Expression * postmutate( VariableExpr * varExpr );
     51                };
    4052        }
    4153
     
    5365                DeclMap declMap;
    5466                replace( node, declMap, typeMap, debug );
     67        }
     68
     69        void replace( BaseSyntaxNode *& node, const ExprMap & exprMap, bool debug ) {
     70                PassVisitor<ExprDeclReplacer> replacer( exprMap, debug );
     71                node = maybeMutate( node, replacer );
    5572        }
    5673
     
    7996                        }
    8097                }
     98
     99                ExprDeclReplacer::ExprDeclReplacer( const ExprMap & exprMap, bool debug ) : exprMap( exprMap ), debug( debug ) {}
     100
     101                Expression * ExprDeclReplacer::postmutate( VariableExpr * varExpr ) {
     102                        if ( exprMap.count( varExpr->var ) ) {
     103                                Expression * replacement = exprMap.at( varExpr->var )->clone();
     104                                if ( debug ) {
     105                                        std::cerr << "replacing variable reference: " << (void*)varExpr->var << " " << varExpr->var << " with " << (void*)replacement << " " << replacement << std::endl;
     106                                }
     107                                std::swap( varExpr->env, replacement->env );
     108                                delete varExpr;
     109                                return replacement;
     110                        }
     111                        return varExpr;
     112                }
    81113        }
    82114} // namespace VarExprReplacer
  • src/SynTree/DeclReplacer.h

    rc786e1d r6054b18  
    2626        typedef std::map< DeclarationWithType *, DeclarationWithType * > DeclMap;
    2727        typedef std::map< TypeDecl *, TypeDecl * > TypeMap;
     28        typedef std::map< DeclarationWithType *, Expression * > ExprMap;
    2829
    2930        void replace( BaseSyntaxNode * node, const DeclMap & declMap, bool debug = false );
    3031        void replace( BaseSyntaxNode * node, const TypeMap & typeMap, bool debug = false );
    3132        void replace( BaseSyntaxNode * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
     33
     34        void replace( BaseSyntaxNode *& node, const ExprMap & exprMap, bool debug = false);
     35        template<typename T>
     36                void replace( T *& node, const ExprMap & exprMap, bool debug = false ) {
     37                if ( ! node ) return;
     38                BaseSyntaxNode * arg = node;
     39                replace( arg, exprMap, debug );
     40                node = dynamic_cast<T *>( arg );
     41                assertf( node, "DeclReplacer fundamentally changed the type of its argument." );
     42        }
    3243}
    3344
  • src/SynTree/Expression.cc

    rc786e1d r6054b18  
    538538        assert( callExpr );
    539539        assert( callExpr->result );
    540         set_result( callExpr->get_result()->clone() );
     540        set_result( callExpr->result->clone() );
    541541}
    542542
    543543ImplicitCopyCtorExpr::ImplicitCopyCtorExpr( const ImplicitCopyCtorExpr & other ) : Expression( other ), callExpr( maybeClone( other.callExpr ) ) {
    544         cloneAll( other.tempDecls, tempDecls );
    545         cloneAll( other.returnDecls, returnDecls );
    546         cloneAll( other.dtors, dtors );
    547544}
    548545
     
    550547        set_env( nullptr ); // ImplicitCopyCtorExpr does not take ownership of an environment
    551548        delete callExpr;
    552         deleteAll( tempDecls );
    553         deleteAll( returnDecls );
    554         deleteAll( dtors );
    555549}
    556550
     
    558552        os <<  "Implicit Copy Constructor Expression: " << std::endl << indent+1;
    559553        callExpr->print( os, indent+1 );
    560         os << std::endl << indent << "... with temporaries:" << std::endl;
    561         printAll( tempDecls, os, indent+1 );
    562         os << std::endl << indent << "... with return temporaries:" << std::endl;
    563         printAll( returnDecls, os, indent+1 );
    564         Expression::print( os, indent );
    565554}
    566555
  • src/SynTree/Expression.h

    rc786e1d r6054b18  
    593593class ImplicitCopyCtorExpr : public Expression {
    594594public:
    595         ApplicationExpr * callExpr;
    596         std::list< ObjectDecl * > tempDecls;
    597         std::list< ObjectDecl * > returnDecls;
    598         std::list< Expression * > dtors;
     595        ApplicationExpr * callExpr = nullptr;
    599596
    600597        ImplicitCopyCtorExpr( ApplicationExpr * callExpr );
    601598        ImplicitCopyCtorExpr( const ImplicitCopyCtorExpr & other );
    602599        virtual ~ImplicitCopyCtorExpr();
    603 
    604         ApplicationExpr * get_callExpr() const { return callExpr; }
    605         void set_callExpr( ApplicationExpr * newValue ) { callExpr = newValue; }
    606 
    607         std::list< ObjectDecl * > & get_tempDecls() { return tempDecls; }
    608         std::list< ObjectDecl * > & get_returnDecls() { return returnDecls; }
    609         std::list< Expression * > & get_dtors() { return dtors; }
    610600
    611601        virtual ImplicitCopyCtorExpr * clone() const { return new ImplicitCopyCtorExpr( * this ); }
  • src/Validate/module.mk

    rc786e1d r6054b18  
    1515###############################################################################
    1616
    17 SRC += Validate/HandleAttributes.cc
    18 SRCDEMANGLE += Validate/HandleAttributes.cc
     17SRC += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
     18SRCDEMANGLE += Validate/HandleAttributes.cc Validate/FindSpecialDecls.cc
  • src/Virtual/ExpandCasts.cc

    rc786e1d r6054b18  
    147147                                //              )
    148148                                //      ),
    149                         new UntypedExpr( new NameExpr( "__cfa__virtual_cast" ), {
     149                        new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    150150                                        new CastExpr(
    151151                                                new AddressExpr( new VariableExpr( table ) ),
    152152                                                pointer_to_pvt(1)
    153                                                 ),
     153                                        ),
    154154                                        new CastExpr(
    155155                                                castExpr->get_arg(),
    156156                                                pointer_to_pvt(2)
    157                                                 )
    158                                 } ),
     157                                        )
     158                        } ),
    159159                        castExpr->get_result()->clone()
    160                         );
     160                );
    161161
    162162                castExpr->set_arg( nullptr );
Note: See TracChangeset for help on using the changeset viewer.