Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/InitTweak/FixInit.cc

    r486341f rb16898e  
    3131#include "SynTree/Mutator.h"
    3232#include "SymTab/Indexer.h"
     33#include "SymTab/Autogen.h"
    3334#include "GenPoly/PolyMutator.h"
    3435#include "SynTree/AddStmtVisitor.h"
     
    176177                };
    177178
    178                 class WarnStructMembers : public Visitor {
     179                class GenStructMemberCalls : public SymTab::Indexer {
    179180                  public:
    180                         typedef Visitor Parent;
    181                         /// warn if a user-defined constructor or destructor is missing calls for
    182                         /// a struct member or if a member is used before constructed
    183                         static void warnings( std::list< Declaration * > & translationUnit );
     181                        typedef Indexer Parent;
     182                        /// generate default/copy ctor and dtor calls for user-defined struct ctor/dtors
     183                        /// for any member that is missing a corresponding ctor/dtor call.
     184                        /// error if a member is used before constructed
     185                        static void generate( std::list< Declaration * > & translationUnit );
    184186
    185187                        virtual void visit( FunctionDecl * funcDecl );
     
    188190                        virtual void visit( ApplicationExpr * appExpr );
    189191
     192                        SemanticError errors;
    190193                  private:
    191194                        void handleFirstParam( Expression * firstParam );
     195                        template< typename... Params >
     196                        void emit( const Params &... params );
    192197
    193198                        FunctionDecl * function = 0;
    194                         std::set< DeclarationWithType * > unhandled;
     199                        std::set< DeclarationWithType * > unhandled, usedUninit;
    195200                        ObjectDecl * thisParam = 0;
     201                        bool isCtor = false; // true if current function is a constructor
     202                        StructDecl * structDecl = 0;
     203                };
     204
     205                // very simple resolver-like mutator class - used to
     206                // resolve UntypedExprs that are found within newly
     207                // generated constructor/destructor calls
     208                class MutatingResolver : public Mutator {
     209                  public:
     210                        MutatingResolver( SymTab::Indexer & indexer ) : indexer( indexer ) {}
     211
     212                        virtual DeclarationWithType* mutate( ObjectDecl *objectDecl );
     213
     214                        virtual Expression* mutate( UntypedExpr *untypedExpr );
     215                        private:
     216                        SymTab::Indexer & indexer;
    196217                };
    197218        } // namespace
     
    209230                FixCopyCtors::fixCopyCtors( translationUnit );
    210231
    211                 WarnStructMembers::warnings( translationUnit );
     232                GenStructMemberCalls::generate( translationUnit );
    212233        }
    213234
     
    254275                }
    255276
    256                 void WarnStructMembers::warnings( std::list< Declaration * > & translationUnit ) {
    257                         if ( true ) { // fix this condition to skip this pass if warnings aren't enabled
    258                                 WarnStructMembers warner;
    259                                 acceptAll( translationUnit, warner );
     277                void GenStructMemberCalls::generate( std::list< Declaration * > & translationUnit ) {
     278                        GenStructMemberCalls warner;
     279                        acceptAll( translationUnit, warner );
     280
     281                        // visitor doesn't throw so that it can collect all errors
     282                        if ( ! warner.errors.isEmpty() ) {
     283                                throw warner.errors;
    260284                        }
    261285                }
     
    528552                                                        FunctionDecl * dtorCaller = new FunctionDecl( objDecl->get_mangleName() + dtorCallerNamer.newName(), DeclarationNode::Static, LinkageSpec::C, new FunctionType( Type::Qualifiers(), false ), new CompoundStmt( noLabels ), false, false );
    529553                                                        dtorCaller->fixUniqueId();
    530                                                         dtorCaller->get_statements()->get_kids().push_back( dtorStmt );
     554                                                        dtorCaller->get_statements()->push_back( dtorStmt );
    531555
    532556                                                        // atexit(dtor_atexit);
     
    543567                                                        // at global scope and there could be multiple function-scoped
    544568                                                        // static variables with the same name in different functions.
     569                                                        // Note: it isn't sufficient to modify only the mangleName, because
     570                                                        // then subsequent Indexer passes can choke on seeing the object's name
     571                                                        // if another object has the same name and type. An unfortunate side-effect
     572                                                        // of renaming the object is that subsequent NameExprs may fail to resolve,
     573                                                        // but there shouldn't be any remaining past this point.
    545574                                                        static UniqueName staticNamer( "_static_var" );
    546                                                         objDecl->set_mangleName( objDecl->get_mangleName() + staticNamer.newName() );
     575                                                        objDecl->set_name( objDecl->get_name() + staticNamer.newName() );
     576                                                        objDecl->set_mangleName( SymTab::Mangler::mangle( objDecl ) );
    547577
    548578                                                        objDecl->set_init( NULL );
     
    709739                }
    710740
    711                 void WarnStructMembers::visit( FunctionDecl * funcDecl ) {
    712                         WarnStructMembers old = *this;
    713                         *this = WarnStructMembers();
     741                void GenStructMemberCalls::visit( FunctionDecl * funcDecl ) {
     742                        ValueGuard< FunctionDecl * > oldFunction( funcDecl );
     743                        ValueGuard< std::set< DeclarationWithType * > > oldUnhandled( unhandled );
     744                        ValueGuard< std::set< DeclarationWithType * > > oldUsedUninit( usedUninit );
     745                        ValueGuard< ObjectDecl * > oldThisParam( thisParam );
     746                        ValueGuard< bool > oldIsCtor( isCtor );
     747                        ValueGuard< StructDecl * > oldStructDecl( structDecl );
     748
     749                        // need to start with fresh sets
     750                        unhandled.clear();
     751                        usedUninit.clear();
    714752
    715753                        function = funcDecl;
    716                         if ( checkWarnings( funcDecl ) ) {
    717                                 FunctionType * type = funcDecl->get_functionType();
     754                        isCtor = isConstructor( function->get_name() );
     755                        if ( checkWarnings( function ) ) {
     756                                FunctionType * type = function->get_functionType();
    718757                                assert( ! type->get_parameters().empty() );
    719758                                thisParam = safe_dynamic_cast< ObjectDecl * >( type->get_parameters().front() );
     
    721760                                StructInstType * structType = dynamic_cast< StructInstType * >( ptrType->get_base() );
    722761                                if ( structType ) {
    723                                         StructDecl * structDecl = structType->get_baseStruct();
     762                                        structDecl = structType->get_baseStruct();
    724763                                        for ( Declaration * member : structDecl->get_members() ) {
    725764                                                if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
     
    731770                                }
    732771                        }
    733                         Parent::visit( funcDecl );
    734 
    735                         for ( DeclarationWithType * member : unhandled ) {
    736                                 // emit a warning for each unhandled member
    737                                 warn( "in ", CodeGen::genType( function->get_functionType(), function->get_name(), false ), ", member ", member->get_name(), " may not have been ", isConstructor( funcDecl->get_name() ) ? "constructed" : "destructed" );
     772                        Parent::visit( function );
     773
     774                        // remove the unhandled objects from usedUninit, because a call is inserted
     775                        // to handle them - only objects that are later constructed are used uninitialized.
     776                        std::set< DeclarationWithType * > diff;
     777                        std::set_difference( usedUninit.begin(), usedUninit.end(), unhandled.begin(), unhandled.end(), std::inserter( diff, diff.begin() ) );
     778                        for ( DeclarationWithType * member : diff ) {
     779                                emit( "in ", CodeGen::genType( function->get_functionType(), function->get_name(), false ), ", field ", member->get_name(), " used before being constructed" );
    738780                        }
    739781
    740                         *this = old;
    741                 }
    742 
    743                 void WarnStructMembers::visit( ApplicationExpr * appExpr ) {
     782                        if ( ! unhandled.empty() ) {
     783                                // need to explicitly re-add function parameters in order to resolve copy constructors
     784                                enterScope();
     785                                maybeAccept( function->get_functionType(), *this );
     786
     787                                // need to iterate through members in reverse in order for
     788                                // ctor/dtor statements to come out in the right order
     789                                for ( Declaration * member : reverseIterate( structDecl->get_members() ) ) {
     790                                        DeclarationWithType * field = dynamic_cast< DeclarationWithType * >( member );
     791                                        // skip non-DWT members
     792                                        if ( ! field ) continue;
     793                                        // skip handled members
     794                                        if ( ! unhandled.count( field ) ) continue;
     795
     796                                        // insert and resolve default/copy constructor call for each field that's unhandled
     797                                        std::list< Statement * > stmt;
     798                                        UntypedExpr * deref = new UntypedExpr( new NameExpr( "*?" ) );
     799                                        deref->get_args().push_back( new VariableExpr( thisParam ) );
     800
     801                                        Expression * arg2 = 0;
     802                                        if ( isCopyConstructor( function ) ) {
     803                                                // if copy ctor, need to pass second-param-of-this-function.field
     804                                                std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
     805                                                assert( params.size() == 2 );
     806                                                arg2 = new MemberExpr( field, new VariableExpr( params.back() ) );
     807                                        }
     808                                        InitExpander srcParam( arg2 );
     809                                        SymTab::genImplicitCall( srcParam, new MemberExpr( field, deref ), function->get_name(), back_inserter( stmt ), field, isCtor );
     810
     811                                        assert( stmt.size() <= 1 );
     812                                        if ( stmt.size() == 1 ) {
     813                                                Statement * callStmt = stmt.front();
     814
     815                                                MutatingResolver resolver( *this );
     816                                                try {
     817                                                        callStmt->acceptMutator( resolver );
     818                                                        if ( isCtor ) {
     819                                                                function->get_statements()->push_front( callStmt );
     820                                                        } else {
     821                                                                // destructor statements should be added at the end
     822                                                                function->get_statements()->push_back( callStmt );
     823                                                        }
     824                                                } catch ( SemanticError & error ) {
     825                                                        emit( "in ", CodeGen::genType( function->get_functionType(), function->get_name(), false ), ", field ", field->get_name(), " not explicitly ", isCtor ? "constructed" : "destructed",  " and no ", isCtor ? "default constructor" : "destructor", " found" );
     826                                                }
     827                                        }
     828                                }
     829                                leaveScope();
     830                        }
     831                }
     832
     833                void GenStructMemberCalls::visit( ApplicationExpr * appExpr ) {
    744834                        if ( ! checkWarnings( function ) ) return;
    745835
     
    760850                                        handleFirstParam( firstParam );
    761851                                }
    762                         } else if ( fname == "?=?" && isIntrinsicCallExpr( appExpr ) ) {
    763                                 // forgive use of intrinsic assignment to construct, since instrinsic constructors
    764                                 // codegen as assignment anyway.
    765                                 assert( appExpr->get_args().size() == 2 );
    766                                 handleFirstParam( appExpr->get_args().front() );
    767852                        }
    768853
     
    770855                }
    771856
    772                 void WarnStructMembers::handleFirstParam( Expression * firstParam ) {
     857                void GenStructMemberCalls::handleFirstParam( Expression * firstParam ) {
    773858                        using namespace std;
    774859                        if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( firstParam ) ) {
     
    787872                }
    788873
    789                 void WarnStructMembers::visit( MemberExpr * memberExpr ) {
     874                void GenStructMemberCalls::visit( MemberExpr * memberExpr ) {
    790875                        if ( ! checkWarnings( function ) ) return;
    791                         if ( ! isConstructor( function->get_name() ) ) return;
     876                        if ( ! isCtor ) return;
    792877
    793878                        if ( ApplicationExpr * deref = dynamic_cast< ApplicationExpr * >( memberExpr->get_aggregate() ) ) {
     
    797882                                                        if ( unhandled.count( memberExpr->get_member() ) ) {
    798883                                                                // emit a warning because a member was used before it was constructed
    799                                                                 warn( "in ", CodeGen::genType( function->get_functionType(), function->get_name(), false ), ", member ", memberExpr->get_member()->get_name(), " used before being constructed" );
     884                                                                usedUninit.insert( memberExpr->get_member() );
    800885                                                        }
    801886                                                }
     
    805890                        Parent::visit( memberExpr );
    806891                }
     892
     893                template< typename Visitor, typename... Params >
     894                void error( Visitor & v, const Params &... params ) {
     895                        v.errors.append( toString( params... ) );
     896                }
     897
     898                template< typename... Params >
     899                void GenStructMemberCalls::emit( const Params &... params ) {
     900                        // toggle warnings vs. errors here.
     901                        // warn( params... );
     902                        error( *this, params... );
     903                }
     904
     905                DeclarationWithType * MutatingResolver::mutate( ObjectDecl *objectDecl ) {
     906                        // add object to the indexer assumes that there will be no name collisions
     907                        // in generated code. If this changes, add mutate methods for entities with
     908                        // scope and call {enter,leave}Scope explicitly.
     909                        objectDecl->accept( indexer );
     910                        return objectDecl;
     911                }
     912
     913                Expression* MutatingResolver::mutate( UntypedExpr *untypedExpr ) {
     914                        return safe_dynamic_cast< ApplicationExpr * >( ResolvExpr::findVoidExpression( untypedExpr, indexer ) );
     915                }
    807916        } // namespace
    808917} // namespace InitTweak
Note: See TracChangeset for help on using the changeset viewer.