Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/GenInit.cc

    r62e5546 r30b65d8  
    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;
     
    136138
    137139        Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) {
    138                 // update for multiple return values
     140                std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
    139141                assert( returnVals.size() == 0 || returnVals.size() == 1 );
    140142                // hands off if the function returns an lvalue - we don't want to allocate a temporary if a variable's address
     
    158160
    159161        DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) {
    160                 ValueGuard< std::list<DeclarationWithType*> > oldReturnVals( returnVals );
     162                // xxx - need to handle named return values - this pass may need to happen
     163                // after resolution? the ordering is tricky because return statements must be
     164                // constructed - the simplest way to do that (while also handling multiple
     165                // returns) is to structure the returnVals into a tuple, as done here.
     166                // however, if the tuple return value is structured before resolution,
     167                // it's difficult to resolve named return values, since the name is lost
     168                // in conversion to a tuple. this might be easiest to deal with
     169                // after reference types are added, as it may then be possible to
     170                // uniformly move named return values to the parameter list directly
     171                ValueGuard< FunctionType * > oldFtype( ftype );
    161172                ValueGuard< std::string > oldFuncName( funcName );
    162173
    163                 FunctionType * type = functionDecl->get_functionType();
    164                 returnVals = type->get_returnVals();
     174                ftype = functionDecl->get_functionType();
     175                std::list< DeclarationWithType * > & retVals = ftype->get_returnVals();
     176                if ( retVals.size() > 1 ) {
     177                        TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) );
     178                        ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) );
     179                        retVals.clear();
     180                        retVals.push_back( newRet );
     181                }
    165182                funcName = functionDecl->get_name();
    166183                DeclarationWithType * decl = Mutator::mutate( functionDecl );
     
    222239        }
    223240
     241        bool CtorDtor::isManaged( Type * type ) const {
     242                if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
     243                        // tuple is also managed if any of its components are managed
     244                        if ( std::any_of( tupleType->get_types().begin(), tupleType->get_types().end(), [&](Type * type) { return isManaged( type ); }) ) {
     245                                return true;
     246                        }
     247                }
     248                // a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
     249                return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end() || GenPoly::isPolyType( type );
     250        }
     251
    224252        bool CtorDtor::isManaged( ObjectDecl * objDecl ) const {
    225253                Type * type = objDecl->get_type();
     
    227255                        type = at->get_base();
    228256                }
    229                 return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();
     257                return isManaged( type );
    230258        }
    231259
     
    238266                        managedTypes.insert( SymTab::Mangler::mangle( type->get_base() ) );
    239267                }
     268        }
     269
     270        ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
     271                // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
     272                // for each constructable object
     273                std::list< Statement * > ctor;
     274                std::list< Statement * > dtor;
     275
     276                InitExpander srcParam( objDecl->get_init() );
     277                InitExpander nullParam( (Initializer *)NULL );
     278                SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
     279                SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     280
     281                // Currently genImplicitCall produces a single Statement - a CompoundStmt
     282                // which  wraps everything that needs to happen. As such, it's technically
     283                // possible to use a Statement ** in the above calls, but this is inherently
     284                // unsafe, so instead we take the slightly less efficient route, but will be
     285                // immediately informed if somehow the above assumption is broken. In this case,
     286                // we could always wrap the list of statements at this point with a CompoundStmt,
     287                // but it seems reasonable at the moment for this to be done by genImplicitCall
     288                // itself. It is possible that genImplicitCall produces no statements (e.g. if
     289                // an array type does not have a dimension). In this case, it's fine to ignore
     290                // the object for the purposes of construction.
     291                assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
     292                if ( ctor.size() == 1 ) {
     293                        // need to remember init expression, in case no ctors exist
     294                        // if ctor does exist, want to use ctor expression instead of init
     295                        // push this decision to the resolver
     296                        assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
     297                        return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
     298                }
     299                return nullptr;
    240300        }
    241301
     
    250310                        if ( ! checkInitDepth( objDecl ) ) throw SemanticError( "Managed object's initializer is too deep ", objDecl );
    251311
    252                         // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    253                         // for each constructable object
    254                         std::list< Statement * > ctor;
    255                         std::list< Statement * > dtor;
    256 
    257                         InitExpander srcParam( objDecl->get_init() );
    258                         InitExpander nullParam( (Initializer *)NULL );
    259                         SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    260                         SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
    261 
    262                         // Currently genImplicitCall produces a single Statement - a CompoundStmt
    263                         // which  wraps everything that needs to happen. As such, it's technically
    264                         // possible to use a Statement ** in the above calls, but this is inherently
    265                         // unsafe, so instead we take the slightly less efficient route, but will be
    266                         // immediately informed if somehow the above assumption is broken. In this case,
    267                         // we could always wrap the list of statements at this point with a CompoundStmt,
    268                         // but it seems reasonable at the moment for this to be done by genImplicitCall
    269                         // itself. It is possible that genImplicitCall produces no statements (e.g. if
    270                         // an array type does not have a dimension). In this case, it's fine to ignore
    271                         // the object for the purposes of construction.
    272                         assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
    273                         if ( ctor.size() == 1 ) {
    274                                 // need to remember init expression, in case no ctors exist
    275                                 // if ctor does exist, want to use ctor expression instead of init
    276                                 // push this decision to the resolver
    277                                 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    278                                 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    279                         }
     312                        objDecl->set_init( genCtorInit( objDecl ) );
    280313                }
    281314                return Parent::mutate( objDecl );
     
    290323                managedTypes.beginScope();
    291324                // go through assertions and recursively add seen ctor/dtors
    292                 for ( TypeDecl * tyDecl : functionDecl->get_functionType()->get_forall() ) {
     325                for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
    293326                        for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
    294327                                assertion = assertion->acceptMutator( *this );
Note: See TracChangeset for help on using the changeset viewer.