Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/GenInit.cc

    rdcd73d1 rf0121d7  
    2929#include "GenPoly/DeclMutator.h"
    3030#include "GenPoly/ScopedSet.h"
     31#include "ResolvExpr/typeops.h"
    3132
    3233namespace InitTweak {
     
    5051
    5152          protected:
    52                 std::list<DeclarationWithType*> returnVals;
     53                FunctionType * ftype;
    5354                UniqueName tempNamer;
    5455                std::string funcName;
     
    8687
    8788                bool isManaged( ObjectDecl * objDecl ) const ; // determine if object is managed
     89                bool isManaged( Type * type ) const; // determine if type is managed
    8890                void handleDWT( DeclarationWithType * dwt ); // add type to managed if ctor/dtor
    8991                GenPoly::ScopedSet< std::string > managedTypes;
     
    134136
    135137        Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) {
    136                 // update for multiple return values
     138                std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
    137139                assert( returnVals.size() == 0 || returnVals.size() == 1 );
    138140                // hands off if the function returns an lvalue - we don't want to allocate a temporary if a variable's address
     
    156158
    157159        DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) {
    158                 ValueGuard< std::list<DeclarationWithType*> > oldReturnVals( returnVals );
     160                // xxx - need to handle named return values - this pass may need to happen
     161                // after resolution? the ordering is tricky because return statements must be
     162                // constructed - the simplest way to do that (while also handling multiple
     163                // returns) is to structure the returnVals into a tuple, as done here.
     164                // however, if the tuple return value is structured before resolution,
     165                // it's difficult to resolve named return values, since the name is lost
     166                // in conversion to a tuple. this might be easiest to deal with
     167                // after reference types are added, as it may then be possible to
     168                // uniformly move named return values to the parameter list directly
     169                ValueGuard< FunctionType * > oldFtype( ftype );
    159170                ValueGuard< std::string > oldFuncName( funcName );
    160171
    161                 FunctionType * type = functionDecl->get_functionType();
    162                 returnVals = type->get_returnVals();
     172                ftype = functionDecl->get_functionType();
     173                std::list< DeclarationWithType * > & retVals = ftype->get_returnVals();
     174                if ( retVals.size() > 1 ) {
     175                        TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) );
     176                        ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) );
     177                        retVals.clear();
     178                        retVals.push_back( newRet );
     179                }
    163180                funcName = functionDecl->get_name();
    164181                DeclarationWithType * decl = Mutator::mutate( functionDecl );
     
    220237        }
    221238
     239        bool CtorDtor::isManaged( Type * type ) const {
     240                if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
     241                        // tuple is also managed if any of its components are managed
     242                        if ( std::any_of( tupleType->get_types().begin(), tupleType->get_types().end(), [&](Type * type) { return isManaged( type ); }) ) {
     243                                return true;
     244                        }
     245                }
     246                return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();
     247        }
     248
    222249        bool CtorDtor::isManaged( ObjectDecl * objDecl ) const {
    223250                Type * type = objDecl->get_type();
     
    225252                        type = at->get_base();
    226253                }
    227                 return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();
     254                return isManaged( type );
    228255        }
    229256
     
    236263                        managedTypes.insert( SymTab::Mangler::mangle( type->get_base() ) );
    237264                }
     265        }
     266
     267        ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
     268                // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
     269                // for each constructable object
     270                std::list< Statement * > ctor;
     271                std::list< Statement * > dtor;
     272
     273                InitExpander srcParam( objDecl->get_init() );
     274                InitExpander nullParam( (Initializer *)NULL );
     275                SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
     276                SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     277
     278                // Currently genImplicitCall produces a single Statement - a CompoundStmt
     279                // which  wraps everything that needs to happen. As such, it's technically
     280                // possible to use a Statement ** in the above calls, but this is inherently
     281                // unsafe, so instead we take the slightly less efficient route, but will be
     282                // immediately informed if somehow the above assumption is broken. In this case,
     283                // we could always wrap the list of statements at this point with a CompoundStmt,
     284                // but it seems reasonable at the moment for this to be done by genImplicitCall
     285                // itself. It is possible that genImplicitCall produces no statements (e.g. if
     286                // an array type does not have a dimension). In this case, it's fine to ignore
     287                // the object for the purposes of construction.
     288                assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
     289                if ( ctor.size() == 1 ) {
     290                        // need to remember init expression, in case no ctors exist
     291                        // if ctor does exist, want to use ctor expression instead of init
     292                        // push this decision to the resolver
     293                        assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
     294                        return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
     295                }
     296                return nullptr;
    238297        }
    239298
     
    248307                        if ( ! checkInitDepth( objDecl ) ) throw SemanticError( "Managed object's initializer is too deep ", objDecl );
    249308
    250                         // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    251                         // for each constructable object
    252                         std::list< Statement * > ctor;
    253                         std::list< Statement * > dtor;
    254 
    255                         InitExpander srcParam( objDecl->get_init() );
    256                         InitExpander nullParam( (Initializer *)NULL );
    257                         SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    258                         SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
    259 
    260                         // Currently genImplicitCall produces a single Statement - a CompoundStmt
    261                         // which  wraps everything that needs to happen. As such, it's technically
    262                         // possible to use a Statement ** in the above calls, but this is inherently
    263                         // unsafe, so instead we take the slightly less efficient route, but will be
    264                         // immediately informed if somehow the above assumption is broken. In this case,
    265                         // we could always wrap the list of statements at this point with a CompoundStmt,
    266                         // but it seems reasonable at the moment for this to be done by genImplicitCall
    267                         // itself. It is possible that genImplicitCall produces no statements (e.g. if
    268                         // an array type does not have a dimension). In this case, it's fine to ignore
    269                         // the object for the purposes of construction.
    270                         assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
    271                         if ( ctor.size() == 1 ) {
    272                                 // need to remember init expression, in case no ctors exist
    273                                 // if ctor does exist, want to use ctor expression instead of init
    274                                 // push this decision to the resolver
    275                                 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    276                                 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    277                         }
     309                        objDecl->set_init( genCtorInit( objDecl ) );
    278310                }
    279311                return Parent::mutate( objDecl );
     
    288320                managedTypes.beginScope();
    289321                // go through assertions and recursively add seen ctor/dtors
    290                 for ( TypeDecl * tyDecl : functionDecl->get_functionType()->get_forall() ) {
     322                for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
    291323                        for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
    292324                                assertion = assertion->acceptMutator( *this );
Note: See TracChangeset for help on using the changeset viewer.