Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/GenInit.cc

    r4d2434a rcad355a  
    2626#include "SymTab/Autogen.h"
    2727#include "GenPoly/PolyMutator.h"
    28 #include "GenPoly/DeclMutator.h"
    2928
    3029namespace InitTweak {
     
    5655          public:
    5756                /// create constructor and destructor statements for object declarations.
    58                 /// the actual call statements will be added in after the resolver has run
    59                 /// so that the initializer expression is only removed if a constructor is found
    60                 /// and the same destructor call is inserted in all of the appropriate locations.
     57                /// Destructors are inserted directly into the code, whereas constructors
     58                /// will be added in after the resolver has run so that the initializer expression
     59                /// is only removed if a constructor is found
    6160                static void generateCtorDtor( std::list< Declaration * > &translationUnit );
     61
     62                CtorDtor() : inFunction( false ) {}
    6263
    6364                virtual DeclarationWithType * mutate( ObjectDecl * );
    6465                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
    65                 // should not traverse into any of these declarations to find objects
    66                 // that need to be constructed or destructed
    67                 virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
    68                 virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
    69                 virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
    70                 virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
    71                 virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; }
    72                 virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; }
    73 
    74                 virtual Type * mutate( FunctionType *funcType ) { return funcType; }
     66                virtual Declaration* mutate( StructDecl *aggregateDecl );
     67                virtual Declaration* mutate( UnionDecl *aggregateDecl );
     68                virtual Declaration* mutate( EnumDecl *aggregateDecl );
     69                virtual Declaration* mutate( TraitDecl *aggregateDecl );
     70                virtual TypeDecl* mutate( TypeDecl *typeDecl );
     71                virtual Declaration* mutate( TypedefDecl *typeDecl );
     72
     73                virtual Type * mutate( FunctionType *funcType );
    7574
    7675          protected:
    77         };
    78 
    79         class HoistArrayDimension : public GenPoly::DeclMutator {
    80           public:
    81                 typedef GenPoly::DeclMutator Parent;
    82 
    83                 /// hoist dimension from array types in object declaration so that it uses a single
    84                 /// const variable of type size_t, so that side effecting array dimensions are only
    85                 /// computed once.
    86                 static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
    87 
    88           private:
    89                 virtual DeclarationWithType * mutate( ObjectDecl * objectDecl );
    90                 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
    91                 // should not traverse into any of these declarations to find objects
    92                 // that need to be constructed or destructed
    93                 virtual Declaration* mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
    94                 virtual Declaration* mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
    95                 virtual Declaration* mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
    96                 virtual Declaration* mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
    97                 virtual TypeDecl* mutate( TypeDecl *typeDecl ) { return typeDecl; }
    98                 virtual Declaration* mutate( TypedefDecl *typeDecl ) { return typeDecl; }
    99 
    100                 virtual Type* mutate( FunctionType *funcType ) { return funcType; }
    101 
    102                 void hoist( Type * type );
    103 
    104                 DeclarationNode::StorageClass storageclass = DeclarationNode::NoStorageClass;
    105                 bool inFunction = false;
     76                bool inFunction;
    10677        };
    10778
    10879        void genInit( std::list< Declaration * > & translationUnit ) {
    10980                ReturnFixer::makeReturnTemp( translationUnit );
    110                 HoistArrayDimension::hoistArrayDimension( translationUnit );
    11181                CtorDtor::generateCtorDtor( translationUnit );
    11282        }
     
    154124        }
    155125
    156         // precompute array dimension expression, because constructor generation may duplicate it,
    157         // which would be incorrect if it is a side-effecting computation.
    158         void HoistArrayDimension::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
    159                 HoistArrayDimension hoister;
    160                 hoister.mutateDeclarationList( translationUnit );
    161         }
    162 
    163         DeclarationWithType * HoistArrayDimension::mutate( ObjectDecl * objectDecl ) {
    164                 storageclass = objectDecl->get_storageClass();
    165                 DeclarationWithType * temp = Parent::mutate( objectDecl );
    166                 hoist( objectDecl->get_type() );
    167                 storageclass = DeclarationNode::NoStorageClass;
    168                 return temp;
    169         }
    170 
    171         void HoistArrayDimension::hoist( Type * type ) {
    172                 // if in function, generate const size_t var
    173                 static UniqueName dimensionName( "_array_dim" );
    174                 if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
    175                         if ( ! inFunction ) return;
    176 
    177                         if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
    178 
    179                         // don't need to hoist dimension if it's a constexpr - only need to if there's potential
    180                         // for side effects.
    181                         if ( isConstExpr( arrayType->get_dimension() ) ) return;
    182 
    183                         ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageclass, LinkageSpec::C, 0, SymTab::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
    184                         arrayDimension->get_type()->set_isConst( true );
    185 
    186                         arrayType->set_dimension( new VariableExpr( arrayDimension ) );
    187                         addDeclaration( arrayDimension );
    188 
    189                         hoist( arrayType->get_base() );
    190                         return;
    191                 }
    192         }
    193 
    194         DeclarationWithType * HoistArrayDimension::mutate( FunctionDecl *functionDecl ) {
    195                 bool oldInFunc = inFunction;
    196                 inFunction = true;
    197                 DeclarationWithType * decl = Parent::mutate( functionDecl );
    198                 inFunction = oldInFunc;
    199                 return decl;
    200         }
    201126
    202127        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
     
    215140
    216141        DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) {
    217                 // hands off if designated, if @=, or if extern
     142                // hands off if designated or if @=
    218143                if ( tryConstruct( objDecl ) ) {
    219                         // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
    220                         // for each constructable object
    221                         std::list< Statement * > ctor;
    222                         std::list< Statement * > dtor;
    223 
    224                         InitExpander srcParam( objDecl->get_init() );
    225                         InitExpander nullParam( (Initializer *)NULL );
    226                         SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
    227                         SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
    228 
    229                         // Currently genImplicitCall produces a single Statement - a CompoundStmt
    230                         // which  wraps everything that needs to happen. As such, it's technically
    231                         // possible to use a Statement ** in the above calls, but this is inherently
    232                         // unsafe, so instead we take the slightly less efficient route, but will be
    233                         // immediately informed if somehow the above assumption is broken. In this case,
    234                         // we could always wrap the list of statements at this point with a CompoundStmt,
    235                         // but it seems reasonable at the moment for this to be done by genImplicitCall
    236                         // itself. It is possible that genImplicitCall produces no statements (e.g. if
    237                         // an array type does not have a dimension). In this case, it's fine to ignore
    238                         // the object for the purposes of construction.
    239                         assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
    240                         if ( ctor.size() == 1 ) {
    241                                 // need to remember init expression, in case no ctors exist
    242                                 // if ctor does exist, want to use ctor expression instead of init
    243                                 // push this decision to the resolver
    244                                 assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
    245                                 objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
     144                        if ( inFunction ) {
     145                                if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->get_type() ) ) {
     146                                        // call into makeArrayFunction from validate.cc to generate calls to ctor/dtor for each element of array
     147                                        // TODO: walk initializer and generate appropriate copy ctor if element has initializer
     148                                        std::list< Expression * > args = makeInitList( objDecl->get_init() );
     149                                        if ( args.empty() ) {
     150                                                std::list< Statement * > ctor;
     151                                                std::list< Statement * > dtor;
     152
     153                                                SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "?{}", back_inserter( ctor ) );
     154                                                SymTab::makeArrayFunction( NULL, new VariableExpr( objDecl ), at, "^?{}", front_inserter( dtor ), false );
     155
     156                                                // Currently makeArrayFunction produces a single Statement - a CompoundStmt
     157                                                // which  wraps everything that needs to happen. As such, it's technically
     158                                                // possible to use a Statement ** in the above calls, but this is inherently
     159                                                // unsafe, so instead we take the slightly less efficient route, but will be
     160                                                // immediately informed if somehow the above assumption is broken. In this case,
     161                                                // we could always wrap the list of statements at this point with a CompoundStmt,
     162                                                // but it seems reasonable at the moment for this to be done by makeArrayFunction
     163                                                // itself
     164                                                assert( ctor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( ctor.front() ) );
     165                                                assert( dtor.size() == 1 && dynamic_cast< ImplicitCtorDtorStmt * >( dtor.front() ) );
     166                                                objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
     167                                        } else {
     168                                                // array came with an initializer list: initialize each element
     169                                                // may have more initializers than elements in the array - need to check at each index that
     170                                                // we haven't exceeded size. This requires precomputing the size because it might be a side-effecting
     171                                                // computation.
     172                                                // may have fewer initializers than eleemnts in the array - need to default construct
     173                                                // remaining elements.
     174                                                // might be able to merge this with the case above.
     175                                        }
     176                                } else {
     177                                        // it's sufficient to attempt to call the ctor/dtor for the given object and its initializer
     178                                        Expression * ctor = makeCtorDtorExpr( "?{}", objDecl, makeInitList( objDecl->get_init() ) );
     179                                        Expression * dtor = makeCtorDtorExpr( "^?{}", objDecl, std::list< Expression * >() );
     180
     181                                        // need to remember init expression, in case no ctors exist
     182                                        // if ctor does exist, want to use ctor expression instead of init
     183                                        // push this decision to the resolver
     184                                        ExprStmt * ctorStmt = new ExprStmt( noLabels, ctor );
     185                                        ExprStmt * dtorStmt = new ExprStmt( noLabels, dtor );
     186                                        objDecl->set_init( new ConstructorInit( new ImplicitCtorDtorStmt( ctorStmt ), new ImplicitCtorDtorStmt( dtorStmt ), objDecl->get_init() ) );
     187                                }
    246188                        }
    247189                }
     
    251193        DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) {
    252194                // parameters should not be constructed and destructed, so don't mutate FunctionType
     195                bool oldInFunc = inFunction;
    253196                mutateAll( functionDecl->get_oldDecls(), *this );
     197                inFunction = true;
    254198                functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
     199                inFunction = oldInFunc;
    255200                return functionDecl;
    256201        }
     202
     203        // should not traverse into any of these declarations to find objects
     204        // that need to be constructed or destructed
     205        Declaration* CtorDtor::mutate( StructDecl *aggregateDecl ) { return aggregateDecl; }
     206        Declaration* CtorDtor::mutate( UnionDecl *aggregateDecl ) { return aggregateDecl; }
     207        Declaration* CtorDtor::mutate( EnumDecl *aggregateDecl ) { return aggregateDecl; }
     208        Declaration* CtorDtor::mutate( TraitDecl *aggregateDecl ) { return aggregateDecl; }
     209        TypeDecl* CtorDtor::mutate( TypeDecl *typeDecl ) { return typeDecl; }
     210        Declaration* CtorDtor::mutate( TypedefDecl *typeDecl ) { return typeDecl; }
     211        Type* CtorDtor::mutate( FunctionType *funcType ) { return funcType; }
     212
    257213} // namespace InitTweak
    258214
Note: See TracChangeset for help on using the changeset viewer.