Changeset c331406 for src/InitTweak


Ignore:
Timestamp:
Aug 5, 2016, 11:03:04 AM (10 years ago)
Author:
Aaron Moss <a3moss@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, stuck-waitfor-destruct, with_gc
Children:
a2f920f
Parents:
5070fe4 (diff), 1b0020a (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 changes from master

Location:
src/InitTweak
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixGlobalInit.cc

    r5070fe4 rc331406  
    4646                FunctionDecl * destroyFunction;
    4747        };
    48 
    49         class ConstExprChecker : public Visitor {
    50         public:
    51                 ConstExprChecker() : isConstExpr( true ) {}
    52 
    53                 virtual void visit( ApplicationExpr *applicationExpr ) { isConstExpr = false; }
    54                 virtual void visit( UntypedExpr *untypedExpr ) { isConstExpr = false; }
    55                 virtual void visit( NameExpr *nameExpr ) { isConstExpr = false; }
    56                 virtual void visit( CastExpr *castExpr ) { isConstExpr = false; }
    57                 virtual void visit( LabelAddressExpr *labAddressExpr ) { isConstExpr = false; }
    58                 virtual void visit( UntypedMemberExpr *memberExpr ) { isConstExpr = false; }
    59                 virtual void visit( MemberExpr *memberExpr ) { isConstExpr = false; }
    60                 virtual void visit( VariableExpr *variableExpr ) { isConstExpr = false; }
    61                 virtual void visit( ConstantExpr *constantExpr ) { /* bottom out */ }
    62                 // these might be okay?
    63                 // virtual void visit( SizeofExpr *sizeofExpr );
    64                 // virtual void visit( AlignofExpr *alignofExpr );
    65                 // virtual void visit( UntypedOffsetofExpr *offsetofExpr );
    66                 // virtual void visit( OffsetofExpr *offsetofExpr );
    67                 // virtual void visit( OffsetPackExpr *offsetPackExpr );
    68                 // virtual void visit( AttrExpr *attrExpr );
    69                 // virtual void visit( CommaExpr *commaExpr );
    70                 // virtual void visit( LogicalExpr *logicalExpr );
    71                 // virtual void visit( ConditionalExpr *conditionalExpr );
    72                 virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; }
    73                 virtual void visit( SolvedTupleExpr *tupleExpr ) { isConstExpr = false; }
    74                 virtual void visit( TypeExpr *typeExpr ) { isConstExpr = false; }
    75                 virtual void visit( AsmExpr *asmExpr ) { isConstExpr = false; }
    76                 virtual void visit( UntypedValofExpr *valofExpr ) { isConstExpr = false; }
    77                 virtual void visit( CompoundLiteralExpr *compLitExpr ) { isConstExpr = false; }
    78 
    79                 bool isConstExpr;
    80         };
    81 
    82         bool isConstExpr( Initializer * init ) {
    83                 if ( init ) {
    84                         ConstExprChecker checker;
    85                         init->accept( checker );
    86                         return checker.isConstExpr;
    87                 } // if
    88                 // for all intents and purposes, no initializer means const expr
    89                 return true;
    90         }
    9148
    9249        void fixGlobalInit( std::list< Declaration * > & translationUnit, const std::string & name, bool inLibrary ) {
     
    14097                std::list< Statement * > & destroyStatements = destroyFunction->get_statements()->get_kids();
    14198
    142                 if ( ! tryConstruct( objDecl ) ) return; // don't construct @= or designated objects
    143                 if ( objDecl->get_storageClass() == DeclarationNode::Extern ) return;
    14499                // C allows you to initialize objects with constant expressions
    145100                // xxx - this is an optimization. Need to first resolve constructors before we decide
     
    147102                // if ( isConstExpr( objDecl->get_init() ) ) return;
    148103
    149                 if ( dynamic_cast< ArrayType * > ( objDecl->get_type() ) ) {
    150                         // xxx - initialize each element of the array
    151                 } else {
    152                         // steal initializer from object and attach it to a new temporary
    153                         ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, objDecl->get_type()->clone(), objDecl->get_init() );
    154                         objDecl->set_init( NULL );
    155                         initStatements.push_back( new DeclStmt( noLabels, newObj ) );
     104                if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
     105                        // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     106                        assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
    156107
    157                         // copy construct objDecl using temporary
    158                         UntypedExpr * init = new UntypedExpr( new NameExpr( "?{}" ) );
    159                         init->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );
    160                         init->get_args().push_back( new VariableExpr( newObj ) );
    161                         initStatements.push_back( new ImplicitCtorDtorStmt( new ExprStmt( noLabels, init ) ) );
    162 
    163                         // add destructor calls to global destroy function
    164                         UntypedExpr * destroy = new UntypedExpr( new NameExpr( "^?{}" ) );
    165                         destroy->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );
    166                         destroyStatements.push_front( new ImplicitCtorDtorStmt( new ExprStmt( noLabels, destroy ) ) );
     108                        Statement * dtor = ctorInit->get_dtor();
     109                        if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
     110                                // don't need to call intrinsic dtor, because it does nothing, but
     111                                // non-intrinsic dtors must be called
     112                                destroyStatements.push_front( dtor );
     113                                ctorInit->set_dtor( NULL );
     114                        } // if
     115                        if ( Statement * ctor = ctorInit->get_ctor() ) {
     116                                initStatements.push_back( ctor );
     117                                objDecl->set_init( NULL );
     118                                ctorInit->set_ctor( NULL );
     119                        } else if ( Initializer * init = ctorInit->get_init() ) {
     120                                objDecl->set_init( init );
     121                                ctorInit->set_init( NULL );
     122                        } else {
     123                                // no constructor and no initializer, which is okay
     124                                objDecl->set_init( NULL );
     125                        } // if
     126                        delete ctorInit;
    167127                } // if
    168128        }
  • src/InitTweak/FixInit.cc

    r5070fe4 rc331406  
    1818#include <iterator>
    1919#include <algorithm>
     20#include "InitTweak.h"
    2021#include "FixInit.h"
    21 #include "InitTweak.h"
     22#include "FixGlobalInit.h"
    2223#include "ResolvExpr/Resolver.h"
    2324#include "ResolvExpr/typeops.h"
     
    2526#include "SynTree/Type.h"
    2627#include "SynTree/Expression.h"
     28#include "SynTree/Attribute.h"
    2729#include "SynTree/Statement.h"
    2830#include "SynTree/Initializer.h"
     
    8385                };
    8486
     87                // debug
    8588                struct printSet {
    8689                        typedef ObjDeclCollector::ObjectSet ObjectSet;
     
    159162
    160163                        virtual DeclarationWithType * mutate( ObjectDecl *objDecl );
     164
     165                        std::list< Declaration * > staticDtorDecls;
    161166                };
    162167
     
    171176        } // namespace
    172177
    173         void fix( std::list< Declaration * > & translationUnit ) {
     178        void fix( std::list< Declaration * > & translationUnit, const std::string & filename, bool inLibrary ) {
     179                // fixes ConstructorInit for global variables. should happen before fixInitializers.
     180                InitTweak::fixGlobalInit( translationUnit, filename, inLibrary );
     181
    174182                InsertImplicitCalls::insert( translationUnit );
    175183                ResolveCopyCtors::resolveImplicitCalls( translationUnit );
     
    194202                void FixInit::fixInitializers( std::list< Declaration * > & translationUnit ) {
    195203                        FixInit fixer;
    196                         mutateAll( translationUnit, fixer );
     204
     205                        // can't use mutateAll, because need to insert declarations at top-level
     206                        // can't use DeclMutator, because sometimes need to insert IfStmt, etc.
     207                        SemanticError errors;
     208                        for ( std::list< Declaration * >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {
     209                                try {
     210                                        *i = maybeMutate( *i, fixer );
     211                                        translationUnit.splice( i, fixer.staticDtorDecls );
     212                                } catch( SemanticError &e ) {
     213                                        errors.append( e );
     214                                } // try
     215                        } // for
     216                        if ( ! errors.isEmpty() ) {
     217                                throw errors;
     218                        } // if
    197219                }
    198220
     
    422444                                if ( Statement * ctor = ctorInit->get_ctor() ) {
    423445                                        if ( objDecl->get_storageClass() == DeclarationNode::Static ) {
     446                                                // originally wanted to take advantage of gcc nested functions, but
     447                                                // we get memory errors with this approach. To remedy this, the static
     448                                                // variable is hoisted when the destructor needs to be called.
     449                                                //
    424450                                                // generate:
    425                                                 // static bool __objName_uninitialized = true;
    426                                                 // if (__objName_uninitialized) {
    427                                                 //   __ctor(__objName);
    428                                                 //   void dtor_atexit() {
    429                                                 //     __dtor(__objName);
     451                                                // static T __objName_static_varN;
     452                                                // void __objName_dtor_atexitN() {
     453                                                //   __dtor__...;
     454                                                // }
     455                                                // int f(...) {
     456                                                //   ...
     457                                                //   static bool __objName_uninitialized = true;
     458                                                //   if (__objName_uninitialized) {
     459                                                //     __ctor(__objName);
     460                                                //     __objName_uninitialized = false;
     461                                                //     atexit(__objName_dtor_atexitN);
    430462                                                //   }
    431                                                 //   on_exit(dtorOnExit, &__objName);
    432                                                 //   __objName_uninitialized = false;
     463                                                //   ...
    433464                                                // }
    434465
    435                                                 // generate first line
     466                                                static UniqueName dtorCallerNamer( "_dtor_atexit" );
     467
     468                                                // static bool __objName_uninitialized = true
    436469                                                BasicType * boolType = new BasicType( Type::Qualifiers(), BasicType::Bool );
    437470                                                SingleInit * boolInitExpr = new SingleInit( new ConstantExpr( Constant( boolType->clone(), "1" ) ), noDesignators );
     
    439472                                                isUninitializedVar->fixUniqueId();
    440473
    441                                                 // void dtor_atexit(...) {...}
    442                                                 FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + "_dtor_atexit", DeclarationNode::NoStorageClass, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false );
    443                                                 dtorCaller->fixUniqueId();
    444                                                 dtorCaller->get_statements()->get_kids().push_back( ctorInit->get_dtor()->clone() );
    445 
    446                                                 // on_exit(dtor_atexit);
    447                                                 UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) );
    448                                                 callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) );
    449 
    450474                                                // __objName_uninitialized = false;
    451475                                                UntypedExpr * setTrue = new UntypedExpr( new NameExpr( "?=?" ) );
     
    457481                                                std::list< Statement * > & body = initStmts->get_kids();
    458482                                                body.push_back( ctor );
    459                                                 body.push_back( new DeclStmt( noLabels, dtorCaller ) );
    460                                                 body.push_back( new ExprStmt( noLabels, callAtexit ) );
    461483                                                body.push_back( new ExprStmt( noLabels, setTrue ) );
    462484
     
    465487                                                stmtsToAddAfter.push_back( new DeclStmt( noLabels, isUninitializedVar ) );
    466488                                                stmtsToAddAfter.push_back( ifStmt );
     489
     490                                                if ( ctorInit->get_dtor() ) {
     491                                                        // if the object has a non-trivial destructor, have to
     492                                                        // hoist it and the object into the global space and
     493                                                        // call the destructor function with atexit.
     494
     495                                                        Statement * dtorStmt = ctorInit->get_dtor()->clone();
     496
     497                                                        // void __objName_dtor_atexitN(...) {...}
     498                                                        FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + dtorCallerNamer.newName(), DeclarationNode::Static, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false );
     499                                                        dtorCaller->fixUniqueId();
     500                                                        dtorCaller->get_statements()->get_kids().push_back( dtorStmt );
     501
     502                                                        // atexit(dtor_atexit);
     503                                                        UntypedExpr * callAtexit = new UntypedExpr( new NameExpr( "atexit" ) );
     504                                                        callAtexit->get_args().push_back( new VariableExpr( dtorCaller ) );
     505
     506                                                        body.push_back( new ExprStmt( noLabels, callAtexit ) );
     507
     508                                                        // hoist variable and dtor caller decls to list of decls that will be added into global scope
     509                                                        staticDtorDecls.push_back( objDecl );
     510                                                        staticDtorDecls.push_back( dtorCaller );
     511
     512                                                        // need to rename object uniquely since it now appears
     513                                                        // at global scope and there could be multiple function-scoped
     514                                                        // static variables with the same name in different functions.
     515                                                        static UniqueName staticNamer( "_static_var" );
     516                                                        objDecl->set_mangleName( objDecl->get_mangleName() + staticNamer.newName() );
     517
     518                                                        objDecl->set_init( NULL );
     519                                                        ctorInit->set_ctor( NULL );
     520                                                        delete ctorInit;
     521
     522                                                        // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
     523                                                        // create a new object which is never used
     524                                                        static UniqueName dummyNamer( "_dummy" );
     525                                                        ObjectDecl * dummy = new ObjectDecl( dummyNamer.newName(), DeclarationNode::Static, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), 0, std::list< Attribute * >{ new Attribute("unused") } );
     526                                                        return dummy;
     527                                                }
    467528                                        } else {
    468529                                                stmtsToAddAfter.push_back( ctor );
     
    524585                                        assert( ! ctorInit->get_ctor() || ! ctorInit->get_init() );
    525586                                        Statement * dtor = ctorInit->get_dtor();
    526                                         if ( dtor && ! isInstrinsicSingleArgCallStmt( dtor ) ) {
     587                                        if ( dtor && ! isIntrinsicSingleArgCallStmt( dtor ) ) {
    527588                                                // don't need to call intrinsic dtor, because it does nothing, but
    528589                                                // non-intrinsic dtors must be called
  • src/InitTweak/FixInit.h

    r5070fe4 rc331406  
    2727  /// replace constructor initializers with expression statements
    2828  /// and unwrap basic C-style initializers
    29         void fix( std::list< Declaration * > & translationUnit );
     29        void fix( std::list< Declaration * > & translationUnit, const std::string & name, bool inLibrary );
    3030} // namespace
    3131
  • src/InitTweak/GenInit.cc

    r5070fe4 rc331406  
    2626#include "SymTab/Autogen.h"
    2727#include "GenPoly/PolyMutator.h"
     28#include "GenPoly/DeclMutator.h"
    2829
    2930namespace InitTweak {
     
    5556          public:
    5657                /// create constructor and destructor statements for object declarations.
    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
     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.
    6061                static void generateCtorDtor( std::list< Declaration * > &translationUnit );
    61 
    62                 CtorDtor() : inFunction( false ) {}
    6362
    6463                virtual DeclarationWithType * mutate( ObjectDecl * );
    6564                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
    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 );
     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; }
    7475
    7576          protected:
    76                 bool inFunction;
     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;
    77106        };
    78107
    79108        void genInit( std::list< Declaration * > & translationUnit ) {
    80109                ReturnFixer::makeReturnTemp( translationUnit );
     110                HoistArrayDimension::hoistArrayDimension( translationUnit );
    81111                CtorDtor::generateCtorDtor( translationUnit );
    82112        }
     
    124154        }
    125155
     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
     175                // C doesn't allow variable sized arrays at global scope or for static variables,
     176                // so don't hoist dimension.
     177                if ( ! inFunction ) return;
     178                if ( storageclass == DeclarationNode::Static ) return;
     179
     180                if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
     181                        if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
     182
     183                        // don't need to hoist dimension if it's a constexpr - only need to if there's potential
     184                        // for side effects.
     185                        if ( isConstExpr( arrayType->get_dimension() ) ) return;
     186
     187                        ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageclass, LinkageSpec::C, 0, SymTab::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
     188                        arrayDimension->get_type()->set_isConst( true );
     189
     190                        arrayType->set_dimension( new VariableExpr( arrayDimension ) );
     191                        addDeclaration( arrayDimension );
     192
     193                        hoist( arrayType->get_base() );
     194                        return;
     195                }
     196        }
     197
     198        DeclarationWithType * HoistArrayDimension::mutate( FunctionDecl *functionDecl ) {
     199                bool oldInFunc = inFunction;
     200                inFunction = true;
     201                DeclarationWithType * decl = Parent::mutate( functionDecl );
     202                inFunction = oldInFunc;
     203                return decl;
     204        }
    126205
    127206        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
     
    130209        }
    131210
    132         namespace {
    133                 Expression * makeCtorDtorExpr( std::string name, ObjectDecl * objDecl, std::list< Expression * > args ) {
    134                         UntypedExpr * expr = new UntypedExpr( new NameExpr( name ) );
    135                         expr->get_args().push_back( new AddressExpr( new VariableExpr( objDecl ) ) );
    136                         expr->get_args().splice( expr->get_args().end(), args );
    137                         return expr;
    138                 }
    139         }
    140 
    141211        DeclarationWithType * CtorDtor::mutate( ObjectDecl * objDecl ) {
    142                 // hands off if designated or if @=
     212                // hands off if designated, if @=, or if extern
    143213                if ( tryConstruct( objDecl ) ) {
    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                                 }
     214                        // call into genImplicitCall from Autogen.h to generate calls to ctor/dtor
     215                        // for each constructable object
     216                        std::list< Statement * > ctor;
     217                        std::list< Statement * > dtor;
     218
     219                        InitExpander srcParam( objDecl->get_init() );
     220                        InitExpander nullParam( (Initializer *)NULL );
     221                        SymTab::genImplicitCall( srcParam, new VariableExpr( objDecl ), "?{}", back_inserter( ctor ), objDecl );
     222                        SymTab::genImplicitCall( nullParam, new VariableExpr( objDecl ), "^?{}", front_inserter( dtor ), objDecl, false );
     223
     224                        // Currently genImplicitCall produces a single Statement - a CompoundStmt
     225                        // which  wraps everything that needs to happen. As such, it's technically
     226                        // possible to use a Statement ** in the above calls, but this is inherently
     227                        // unsafe, so instead we take the slightly less efficient route, but will be
     228                        // immediately informed if somehow the above assumption is broken. In this case,
     229                        // we could always wrap the list of statements at this point with a CompoundStmt,
     230                        // but it seems reasonable at the moment for this to be done by genImplicitCall
     231                        // itself. It is possible that genImplicitCall produces no statements (e.g. if
     232                        // an array type does not have a dimension). In this case, it's fine to ignore
     233                        // the object for the purposes of construction.
     234                        assert( ctor.size() == dtor.size() && ctor.size() <= 1 );
     235                        if ( ctor.size() == 1 ) {
     236                                // need to remember init expression, in case no ctors exist
     237                                // if ctor does exist, want to use ctor expression instead of init
     238                                // push this decision to the resolver
     239                                assert( dynamic_cast< ImplicitCtorDtorStmt * > ( ctor.front() ) && dynamic_cast< ImplicitCtorDtorStmt * > ( dtor.front() ) );
     240                                objDecl->set_init( new ConstructorInit( ctor.front(), dtor.front(), objDecl->get_init() ) );
    188241                        }
    189242                }
     
    193246        DeclarationWithType * CtorDtor::mutate( FunctionDecl *functionDecl ) {
    194247                // parameters should not be constructed and destructed, so don't mutate FunctionType
    195                 bool oldInFunc = inFunction;
    196248                mutateAll( functionDecl->get_oldDecls(), *this );
    197                 inFunction = true;
    198249                functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
    199                 inFunction = oldInFunc;
    200250                return functionDecl;
    201251        }
    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 
    213252} // namespace InitTweak
    214253
  • src/InitTweak/InitTweak.cc

    r5070fe4 rc331406  
     1#include <algorithm>
    12#include "InitTweak.h"
    23#include "SynTree/Visitor.h"
     
    45#include "SynTree/Initializer.h"
    56#include "SynTree/Expression.h"
     7#include "SynTree/Attribute.h"
    68#include "GenPoly/GenPoly.h"
    79
     
    2022                };
    2123
    22                 class InitExpander : public Visitor {
     24                class InitFlattener : public Visitor {
    2325                        public:
    24                         InitExpander() {}
    2526                        virtual void visit( SingleInit * singleInit );
    2627                        virtual void visit( ListInit * listInit );
     
    2829                };
    2930
    30                 void InitExpander::visit( SingleInit * singleInit ) {
     31                void InitFlattener::visit( SingleInit * singleInit ) {
    3132                        argList.push_back( singleInit->get_value()->clone() );
    3233                }
    3334
    34                 void InitExpander::visit( ListInit * listInit ) {
    35                         // xxx - for now, assume no nested list inits
    36                         std::list<Initializer*>::iterator it = listInit->begin_initializers();
    37                         for ( ; it != listInit->end_initializers(); ++it ) {
     35                void InitFlattener::visit( ListInit * listInit ) {
     36                        // flatten nested list inits
     37                        std::list<Initializer*>::iterator it = listInit->begin();
     38                        for ( ; it != listInit->end(); ++it ) {
    3839                                (*it)->accept( *this );
    3940                        }
     
    4243
    4344        std::list< Expression * > makeInitList( Initializer * init ) {
    44                 InitExpander expander;
    45                 maybeAccept( init, expander );
    46                 return expander.argList;
     45                InitFlattener flattener;
     46                maybeAccept( init, flattener );
     47                return flattener.argList;
    4748        }
    4849
     
    5354        }
    5455
     56        class InitExpander::ExpanderImpl {
     57        public:
     58                virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0;
     59                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0;
     60        };
     61
     62        class InitImpl : public InitExpander::ExpanderImpl {
     63        public:
     64                InitImpl( Initializer * init ) : init( init ) {}
     65
     66                virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
     67                        // this is wrong, but just a placeholder for now
     68                        // if ( ! flattened ) flatten( indices );
     69                        // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >();
     70                        return makeInitList( init );
     71                }
     72
     73                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
     74        private:
     75                Initializer * init;
     76        };
     77
     78        class ExprImpl : public InitExpander::ExpanderImpl {
     79        public:
     80                ExprImpl( Expression * expr ) : arg( expr ) {}
     81
     82                virtual std::list< Expression * > next( std::list< Expression * > & indices ) {
     83                        std::list< Expression * > ret;
     84                        Expression * expr = maybeClone( arg );
     85                        if ( expr ) {
     86                                for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) {
     87                                        // go through indices and layer on subscript exprs ?[?]
     88                                        ++it;
     89                                        UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") );
     90                                        subscriptExpr->get_args().push_back( expr );
     91                                        subscriptExpr->get_args().push_back( (*it)->clone() );
     92                                        expr = subscriptExpr;
     93                                }
     94                                ret.push_back( expr );
     95                        }
     96                        return ret;
     97                }
     98
     99                virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices );
     100        private:
     101                Expression * arg;
     102        };
     103
     104        InitExpander::InitExpander( Initializer * init ) : expander( new InitImpl( init ) ) {}
     105
     106        InitExpander::InitExpander( Expression * expr ) : expander( new ExprImpl( expr ) ) {}
     107
     108        std::list< Expression * > InitExpander::operator*() {
     109                return cur;
     110        }
     111
     112        InitExpander & InitExpander::operator++() {
     113                cur = expander->next( indices );
     114                return *this;
     115        }
     116
     117        // use array indices list to build switch statement
     118        void InitExpander::addArrayIndex( Expression * index, Expression * dimension ) {
     119                indices.push_back( index );
     120                indices.push_back( dimension );
     121        }
     122
     123        void InitExpander::clearArrayIndices() {
     124                indices.clear();
     125        }
     126
     127        namespace {
     128                /// given index i, dimension d, initializer init, and callExpr f, generates
     129                ///   if (i < d) f(..., init)
     130                ///   ++i;
     131                /// so that only elements within the range of the array are constructed
     132                template< typename OutIterator >
     133                void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) {
     134                        UntypedExpr * cond = new UntypedExpr( new NameExpr( "?<?") );
     135                        cond->get_args().push_back( index->clone() );
     136                        cond->get_args().push_back( dimension->clone() );
     137
     138                        std::list< Expression * > args = makeInitList( init );
     139                        callExpr->get_args().splice( callExpr->get_args().end(), args );
     140
     141                        *out++ = new IfStmt( noLabels, cond, new ExprStmt( noLabels, callExpr ), NULL );
     142
     143                        UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) );
     144                        increment->get_args().push_back( new AddressExpr( index->clone() ) );
     145                        *out++ = new ExprStmt( noLabels, increment );
     146                }
     147
     148                template< typename OutIterator >
     149                void build( UntypedExpr * callExpr, InitExpander::IndexList::iterator idx, InitExpander::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) {
     150                        if ( idx == idxEnd ) return;
     151                        Expression * index = *idx++;
     152                        assert( idx != idxEnd );
     153                        Expression * dimension = *idx++;
     154
     155                        // xxx - may want to eventually issue a warning here if we can detect
     156                        // that the number of elements exceeds to dimension of the array
     157                        if ( idx == idxEnd ) {
     158                                if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) {
     159                                        for ( Initializer * init : *listInit ) {
     160                                                buildCallExpr( callExpr->clone(), index, dimension, init, out );
     161                                        }
     162                                } else {
     163                                        buildCallExpr( callExpr->clone(), index, dimension, init, out );
     164                                }
     165                        } else {
     166                                std::list< Statement * > branches;
     167
     168                                unsigned long cond = 0;
     169                                ListInit * listInit = dynamic_cast< ListInit * >( init );
     170                                if ( ! listInit ) {
     171                                        // xxx - this shouldn't be an error, but need a way to
     172                                        // terminate without creating output, so should catch this error
     173                                        throw SemanticError( "unbalanced list initializers" );
     174                                }
     175
     176                                static UniqueName targetLabel( "L__autogen__" );
     177                                Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } );
     178                                for ( Initializer * init : *listInit ) {
     179                                        Expression * condition;
     180                                        // check for designations
     181                                        // if ( init-> ) {
     182                                                condition = new ConstantExpr( Constant::from_ulong( cond ) );
     183                                                ++cond;
     184                                        // } else {
     185                                        //      condition = // ... take designation
     186                                        //      cond = // ... take designation+1
     187                                        // }
     188                                        std::list< Statement * > stmts;
     189                                        build( callExpr, idx, idxEnd, init, back_inserter( stmts ) );
     190                                        stmts.push_back( new BranchStmt( noLabels, switchLabel, BranchStmt::Break ) );
     191                                        CaseStmt * caseStmt = new CaseStmt( noLabels, condition, stmts );
     192                                        branches.push_back( caseStmt );
     193                                }
     194                                *out++ = new SwitchStmt( noLabels, index->clone(), branches );
     195                                *out++ = new NullStmt( std::list<Label>{ switchLabel } );
     196                        }
     197                }
     198        }
     199
     200        // if array came with an initializer list: initialize each element
     201        // may have more initializers than elements in the array - need to check at each index that
     202        // we haven't exceeded size.
     203        // may have fewer initializers than elements in the array - need to default construct
     204        // remaining elements.
     205        // To accomplish this, generate switch statement, consuming all of expander's elements
     206        Statement * InitImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
     207                if ( ! init ) return NULL;
     208                CompoundStmt * block = new CompoundStmt( noLabels );
     209                build( dst, indices.begin(), indices.end(), init, back_inserter( block->get_kids() ) );
     210                if ( block->get_kids().empty() ) {
     211                        delete block;
     212                        return NULL;
     213                } else {
     214                        init = NULL; // init was consumed in creating the list init
     215                        return block;
     216                }
     217        }
     218
     219        Statement * ExprImpl::buildListInit( UntypedExpr * dst, std::list< Expression * > & indices ) {
     220                return NULL;
     221        }
     222
     223        Statement * InitExpander::buildListInit( UntypedExpr * dst ) {
     224                return expander->buildListInit( dst, indices );
     225        }
     226
    55227        bool tryConstruct( ObjectDecl * objDecl ) {
    56228                return ! LinkageSpec::isBuiltin( objDecl->get_linkage() ) &&
    57229                        (objDecl->get_init() == NULL ||
    58230                                ( objDecl->get_init() != NULL && objDecl->get_init()->get_maybeConstructed() )) &&
    59                         ! isDesignated( objDecl->get_init() );
     231                        ! isDesignated( objDecl->get_init() )
     232                        && objDecl->get_storageClass() != DeclarationNode::Extern;
     233        }
     234
     235        class CallFinder : public Visitor {
     236        public:
     237                typedef Visitor Parent;
     238                CallFinder( const std::list< std::string > & names ) : names( names ) {}
     239
     240                virtual void visit( ApplicationExpr * appExpr ) {
     241                        handleCallExpr( appExpr );
     242                }
     243
     244                virtual void visit( UntypedExpr * untypedExpr ) {
     245                        handleCallExpr( untypedExpr );
     246                }
     247
     248                std::list< Expression * > * matches;
     249        private:
     250                const std::list< std::string > names;
     251
     252                template< typename CallExpr >
     253                void handleCallExpr( CallExpr * expr ) {
     254                        Parent::visit( expr );
     255                        std::string fname = getFunctionName( expr );
     256                        if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
     257                                matches->push_back( expr );
     258                        }
     259                }
     260        };
     261
     262        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches ) {
     263                static CallFinder finder( std::list< std::string >{ "?{}", "^?{}" } );
     264                finder.matches = &matches;
     265                maybeAccept( stmt, finder );
    60266        }
    61267
    62268        Expression * getCtorDtorCall( Statement * stmt ) {
    63                 if ( stmt == NULL ) return NULL;
    64                 if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( stmt ) ) {
    65                         return exprStmt->get_expr();
    66                 } else if ( CompoundStmt * compoundStmt = dynamic_cast< CompoundStmt * >( stmt ) ) {
    67                         // could also be a compound statement with a loop, in the case of an array
    68                         if( compoundStmt->get_kids().size() == 2 ) {
    69                                 // loop variable and loop
    70                                 ForStmt * forStmt = dynamic_cast< ForStmt * >( compoundStmt->get_kids().back() );
    71                                 assert( forStmt && forStmt->get_body() );
    72                                 return getCtorDtorCall( forStmt->get_body() );
    73                         } else if ( compoundStmt->get_kids().size() == 1 ) {
    74                                 // should be the call statement, but in any case there's only one option
    75                                 return getCtorDtorCall( compoundStmt->get_kids().front() );
    76                         } else {
    77                                 assert( false && "too many statements in compoundStmt for getCtorDtorCall" );
    78                         }
    79                 } if ( ImplicitCtorDtorStmt * impCtorDtorStmt = dynamic_cast< ImplicitCtorDtorStmt * > ( stmt ) ) {
    80                         return getCtorDtorCall( impCtorDtorStmt->get_callStmt() );
    81                 } else {
    82                         // should never get here
    83                         assert( false && "encountered unknown call statement" );
    84                 }
    85         }
    86 
    87         bool isInstrinsicSingleArgCallStmt( Statement * stmt ) {
    88                 Expression * callExpr = getCtorDtorCall( stmt );
    89                 if ( ! callExpr ) return false;
    90                 ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( callExpr );
    91                 assert( appExpr );
    92                 VariableExpr * function = dynamic_cast< VariableExpr * >( appExpr->get_function() );
     269                std::list< Expression * > matches;
     270                collectCtorDtorCalls( stmt, matches );
     271                assert( matches.size() <= 1 );
     272                return matches.size() == 1 ? matches.front() : NULL;
     273        }
     274
     275        namespace {
     276                VariableExpr * getCalledFunction( ApplicationExpr * appExpr ) {
     277                        assert( appExpr );
     278                        // xxx - it's possible this can be other things, e.g. MemberExpr, so this is insufficient
     279                        return dynamic_cast< VariableExpr * >( appExpr->get_function() );
     280                }
     281        }
     282
     283        ApplicationExpr * isIntrinsicCallExpr( Expression * expr ) {
     284                ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr );
     285                if ( ! appExpr ) return NULL;
     286                VariableExpr * function = getCalledFunction( appExpr );
    93287                assert( function );
    94288                // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor
    95289                // will call all member dtors, and some members may have a user defined dtor.
    96                 FunctionType * funcType = GenPoly::getFunctionType( function->get_var()->get_type() );
    97                 assert( funcType );
    98                 return function->get_var()->get_linkage() == LinkageSpec::Intrinsic && funcType->get_parameters().size() == 1;
     290                return function->get_var()->get_linkage() == LinkageSpec::Intrinsic ? appExpr : NULL;
     291        }
     292
     293        bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {
     294                std::list< Expression * > callExprs;
     295                collectCtorDtorCalls( stmt, callExprs );
     296                // if ( callExprs.empty() ) return false; // xxx - do I still need this check?
     297                return std::all_of( callExprs.begin(), callExprs.end(), []( Expression * callExpr ){
     298                        if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
     299                                assert( ! appExpr->get_function()->get_results().empty() );
     300                                FunctionType *funcType = GenPoly::getFunctionType( appExpr->get_function()->get_results().front() );
     301                                assert( funcType );
     302                                return funcType->get_parameters().size() == 1;
     303                        }
     304                        return false;
     305                });
    99306        }
    100307
     
    160367                else return NULL;
    161368        }
     369
     370        class ConstExprChecker : public Visitor {
     371        public:
     372                ConstExprChecker() : isConstExpr( true ) {}
     373
     374                virtual void visit( ApplicationExpr *applicationExpr ) { isConstExpr = false; }
     375                virtual void visit( UntypedExpr *untypedExpr ) { isConstExpr = false; }
     376                virtual void visit( NameExpr *nameExpr ) { isConstExpr = false; }
     377                virtual void visit( CastExpr *castExpr ) { isConstExpr = false; }
     378                virtual void visit( LabelAddressExpr *labAddressExpr ) { isConstExpr = false; }
     379                virtual void visit( UntypedMemberExpr *memberExpr ) { isConstExpr = false; }
     380                virtual void visit( MemberExpr *memberExpr ) { isConstExpr = false; }
     381                virtual void visit( VariableExpr *variableExpr ) { isConstExpr = false; }
     382                virtual void visit( ConstantExpr *constantExpr ) { /* bottom out */ }
     383                // these might be okay?
     384                // virtual void visit( SizeofExpr *sizeofExpr );
     385                // virtual void visit( AlignofExpr *alignofExpr );
     386                // virtual void visit( UntypedOffsetofExpr *offsetofExpr );
     387                // virtual void visit( OffsetofExpr *offsetofExpr );
     388                // virtual void visit( OffsetPackExpr *offsetPackExpr );
     389                // virtual void visit( AttrExpr *attrExpr );
     390                // virtual void visit( CommaExpr *commaExpr );
     391                // virtual void visit( LogicalExpr *logicalExpr );
     392                // virtual void visit( ConditionalExpr *conditionalExpr );
     393                virtual void visit( TupleExpr *tupleExpr ) { isConstExpr = false; }
     394                virtual void visit( SolvedTupleExpr *tupleExpr ) { isConstExpr = false; }
     395                virtual void visit( TypeExpr *typeExpr ) { isConstExpr = false; }
     396                virtual void visit( AsmExpr *asmExpr ) { isConstExpr = false; }
     397                virtual void visit( UntypedValofExpr *valofExpr ) { isConstExpr = false; }
     398                virtual void visit( CompoundLiteralExpr *compLitExpr ) { isConstExpr = false; }
     399
     400                bool isConstExpr;
     401        };
     402
     403        bool isConstExpr( Expression * expr ) {
     404                if ( expr ) {
     405                        ConstExprChecker checker;
     406                        expr->accept( checker );
     407                        return checker.isConstExpr;
     408                }
     409                return true;
     410        }
     411
     412        bool isConstExpr( Initializer * init ) {
     413                if ( init ) {
     414                        ConstExprChecker checker;
     415                        init->accept( checker );
     416                        return checker.isConstExpr;
     417                } // if
     418                // for all intents and purposes, no initializer means const expr
     419                return true;
     420        }
     421
    162422}
  • src/InitTweak/InitTweak.h

    r5070fe4 rc331406  
    2626// helper functions for initialization
    2727namespace InitTweak {
    28   /// transform Initializer into an argument list that can be passed to a call expression
    29   std::list< Expression * > makeInitList( Initializer * init );
     28        /// transform Initializer into an argument list that can be passed to a call expression
     29        std::list< Expression * > makeInitList( Initializer * init );
    3030
    31   /// True if the resolver should try to construct objDecl
    32   bool tryConstruct( ObjectDecl * objDecl );
     31        /// True if the resolver should try to construct objDecl
     32        bool tryConstruct( ObjectDecl * objDecl );
    3333
    34   /// True if the Initializer contains designations
    35   bool isDesignated( Initializer * init );
     34        /// True if the Initializer contains designations
     35        bool isDesignated( Initializer * init );
    3636
    37   /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
    38   /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
    39   /// Currently has assertions that make it less than fully general.
    40   bool isInstrinsicSingleArgCallStmt( Statement * expr );
     37  /// Non-Null if expr is a call expression whose target function is intrinsic
     38  ApplicationExpr * isIntrinsicCallExpr( Expression * expr );
    4139
    42   /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
    43   Expression * getCtorDtorCall( Statement * stmt );
     40        /// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
     41        /// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
     42        /// Currently has assertions that make it less than fully general.
     43        bool isIntrinsicSingleArgCallStmt( Statement * expr );
    4444
    45   /// returns the name of the function being called
    46   std::string getFunctionName( Expression * expr );
     45        /// get all Ctor/Dtor call expressions from a Statement
     46        void collectCtorDtorCalls( Statement * stmt, std::list< Expression * > & matches );
    4747
    48   /// returns the argument to a call expression in position N indexed from 0
    49   Expression *& getCallArg( Expression * callExpr, unsigned int pos );
     48        /// get the Ctor/Dtor call expression from a Statement that looks like a generated ctor/dtor call
     49        Expression * getCtorDtorCall( Statement * stmt );
    5050
    51   /// returns the base type of a PointerType or ArrayType, else returns NULL
    52   Type * getPointerBase( Type * );
     51        /// returns the name of the function being called
     52        std::string getFunctionName( Expression * expr );
    5353
    54   /// returns the argument if it is a PointerType or ArrayType, else returns NULL
    55   Type * isPointerType( Type * );
     54        /// returns the argument to a call expression in position N indexed from 0
     55        Expression *& getCallArg( Expression * callExpr, unsigned int pos );
     56
     57        /// returns the base type of a PointerType or ArrayType, else returns NULL
     58        Type * getPointerBase( Type * );
     59
     60        /// returns the argument if it is a PointerType or ArrayType, else returns NULL
     61        Type * isPointerType( Type * );
     62
     63        /// returns true if expr is trivially a compile-time constant
     64        bool isConstExpr( Expression * expr );
     65        bool isConstExpr( Initializer * init );
     66
     67        class InitExpander {
     68        public:
     69                // expand by stepping through init to get each list of arguments
     70                InitExpander( Initializer * init );
     71
     72                // always expand to expr
     73                InitExpander( Expression * expr );
     74
     75                // iterator-like interface
     76                std::list< Expression * > operator*();
     77                InitExpander & operator++();
     78
     79                // builds statement which has the same semantics as a C-style list initializer
     80                // (for array initializers) using callExpr as the base expression to perform initialization
     81                Statement * buildListInit( UntypedExpr * callExpr );
     82                void addArrayIndex( Expression * index, Expression * dimension );
     83                void clearArrayIndices();
     84
     85                class ExpanderImpl;
     86        private:
     87                std::shared_ptr< ExpanderImpl > expander;
     88                std::list< Expression * > cur;
     89
     90                // invariant: list of size 2N (elements come in pairs [index, dimension])
     91                typedef std::list< Expression * > IndexList;
     92                IndexList indices;
     93        };
    5694} // namespace
    5795
Note: See TracChangeset for help on using the changeset viewer.