Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/GenInit.cc

    r62e5546 r9facf3b  
    2929#include "GenPoly/DeclMutator.h"
    3030#include "GenPoly/ScopedSet.h"
     31#include "ResolvExpr/typeops.h"
    3132
    3233namespace InitTweak {
     
    4546                ReturnFixer();
    4647
    47                 using GenPoly::PolyMutator::mutate;
     48                typedef GenPoly::PolyMutator Parent;
     49                using Parent::mutate;
    4850                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override;
    4951                virtual Statement * mutate( ReturnStmt * returnStmt ) override;
    5052
    5153          protected:
    52                 std::list<DeclarationWithType*> returnVals;
    53                 UniqueName tempNamer;
     54                FunctionType * ftype;
    5455                std::string funcName;
    5556        };
     
    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;
     
    133135        }
    134136
    135         ReturnFixer::ReturnFixer() : tempNamer( "_retVal" ) {}
     137        ReturnFixer::ReturnFixer() {}
    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
    141143                // is being returned
     144                // Note: under the assumption that assignments return *this, checking for ?=? here is an optimization, since it shouldn't be necessary to copy construct `this`. This is a temporary optimization until reference types are added, at which point this should be removed, along with the analogous optimization in copy constructor generation.
    142145                if ( returnStmt->get_expr() && returnVals.size() == 1 && funcName != "?=?" && ! returnVals.front()->get_type()->get_isLvalue() ) {
    143                         // ensure return value is not destructed by explicitly creating
    144                         // an empty SingleInit node wherein maybeConstruct is false
    145                         ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, returnVals.front()->get_type()->clone(), new ListInit( std::list<Initializer*>(), noDesignators, false ) );
    146                         stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) );
    147 
    148                         // and explicitly create the constructor expression separately
     146                        // explicitly construct the return value using the return expression and the retVal object
     147                        assertf( returnVals.front()->get_name() != "", "Function %s has unnamed return value\n", funcName.c_str() );
    149148                        UntypedExpr *construct = new UntypedExpr( new NameExpr( "?{}" ) );
    150                         construct->get_args().push_back( new AddressExpr( new VariableExpr( newObj ) ) );
     149                        construct->get_args().push_back( new AddressExpr( new VariableExpr( returnVals.front() ) ) );
    151150                        construct->get_args().push_back( returnStmt->get_expr() );
    152151                        stmtsToAdd.push_back(new ExprStmt(noLabels, construct));
    153152
    154                         returnStmt->set_expr( new VariableExpr( newObj ) );
     153                        // return the retVal object
     154                        returnStmt->set_expr( new VariableExpr( returnVals.front() ) );
    155155                } // if
    156156                return returnStmt;
     
    158158
    159159        DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) {
    160                 ValueGuard< std::list<DeclarationWithType*> > oldReturnVals( returnVals );
     160                ValueGuard< FunctionType * > oldFtype( ftype );
    161161                ValueGuard< std::string > oldFuncName( funcName );
    162162
    163                 FunctionType * type = functionDecl->get_functionType();
    164                 returnVals = type->get_returnVals();
     163                ftype = functionDecl->get_functionType();
    165164                funcName = functionDecl->get_name();
    166                 DeclarationWithType * decl = Mutator::mutate( functionDecl );
    167                 return decl;
     165                return Parent::mutate( functionDecl );
    168166        }
    169167
     
    222220        }
    223221
     222        bool CtorDtor::isManaged( Type * type ) const {
     223                if ( TupleType * tupleType = dynamic_cast< TupleType * > ( type ) ) {
     224                        // tuple is also managed if any of its components are managed
     225                        if ( std::any_of( tupleType->get_types().begin(), tupleType->get_types().end(), [&](Type * type) { return isManaged( type ); }) ) {
     226                                return true;
     227                        }
     228                }
     229                // 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)
     230                return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end() || GenPoly::isPolyType( type );
     231        }
     232
    224233        bool CtorDtor::isManaged( ObjectDecl * objDecl ) const {
    225234                Type * type = objDecl->get_type();
     
    227236                        type = at->get_base();
    228237                }
    229                 return managedTypes.find( SymTab::Mangler::mangle( type ) ) != managedTypes.end();
     238                return isManaged( type );
    230239        }
    231240
     
    238247                        managedTypes.insert( SymTab::Mangler::mangle( type->get_base() ) );
    239248                }
     249        }
     250
     251        ConstructorInit * genCtorInit( ObjectDecl * objDecl ) {
     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                        return new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() );
     279                }
     280                return nullptr;
    240281        }
    241282
     
    250291                        if ( ! checkInitDepth( objDecl ) ) throw SemanticError( "Managed object's initializer is too deep ", objDecl );
    251292
    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                         }
     293                        objDecl->set_init( genCtorInit( objDecl ) );
    280294                }
    281295                return Parent::mutate( objDecl );
     
    290304                managedTypes.beginScope();
    291305                // go through assertions and recursively add seen ctor/dtors
    292                 for ( TypeDecl * tyDecl : functionDecl->get_functionType()->get_forall() ) {
     306                for ( auto & tyDecl : functionDecl->get_functionType()->get_forall() ) {
    293307                        for ( DeclarationWithType *& assertion : tyDecl->get_assertions() ) {
    294308                                assertion = assertion->acceptMutator( *this );
Note: See TracChangeset for help on using the changeset viewer.