Ignore:
Timestamp:
Jan 23, 2017, 11:42:09 AM (7 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
092528b
Parents:
bd98b58
Message:

disable autogeneration of ctor/dtor/assign when a member's corresponding operation is missing

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/SymTab/Autogen.cc

    rbd98b58 r207c7e1d  
    2525#include "Autogen.h"
    2626#include "GenPoly/ScopedSet.h"
     27#include "Common/ScopedMap.h"
    2728#include "SymTab/Mangler.h"
    2829#include "GenPoly/DeclMutator.h"
     
    3031namespace SymTab {
    3132        Type * SizeType = 0;
    32 
    33         class AutogenerateRoutines : public Visitor {
     33        typedef ScopedMap< std::string, bool > TypeMap;
     34
     35        /// Data used to generate functions generically. Specifically, the name of the generated function, a function which generates the routine protoype, and a map which contains data to determine whether a function should be generated.
     36        struct FuncData {
     37                typedef FunctionType * (*TypeGen)( Type * );
     38                FuncData( const std::string & fname, const TypeGen & genType, TypeMap & map ) : fname( fname ), genType( genType ), map( map ) {}
     39                std::string fname;
     40                TypeGen genType;
     41                TypeMap & map;
     42        };
     43
     44        class AutogenerateRoutines final : public Visitor {
    3445          public:
    3546                std::list< Declaration * > &get_declsToAdd() { return declsToAdd; }
     
    3748                typedef Visitor Parent;
    3849                using Parent::visit;
     50
     51                AutogenerateRoutines();
    3952
    4053                virtual void visit( EnumDecl *enumDecl );
     
    5770                std::set< std::string > structsDone;
    5871                unsigned int functionNesting = 0;     // current level of nested functions
     72                /// Note: the following maps could be ScopedSets, but it should be easier to work
     73                /// deleted functions in if they are maps, since the value false can be inserted
     74                /// at the current scope without affecting outer scopes or requiring copies.
     75                TypeMap copyable, assignable, constructable, destructable;
     76                std::vector< FuncData > data;
    5977        };
    6078
     
    144162                decl->fixUniqueId();
    145163                return decl;
     164        }
     165
     166        /// inserts base type of first argument into map if pred(funcDecl) is true
     167        void insert( FunctionDecl *funcDecl, TypeMap & map, FunctionDecl * (*pred)(Declaration *) ) {
     168                // insert type into constructable, etc. map if appropriate
     169                if ( pred( funcDecl ) ) {
     170                        FunctionType * ftype = funcDecl->get_functionType();
     171                        assert( ! ftype->get_parameters().empty() );
     172                        Type * t = safe_dynamic_cast< PointerType * >( ftype->get_parameters().front()->get_type() )->get_base();
     173                        map.insert( Mangler::mangleType( t ), true );
     174                }
     175        }
     176
     177        /// using map and t, determines if is constructable, etc.
     178        bool lookup( const TypeMap & map, Type * t ) {
     179                if ( dynamic_cast< PointerType * >( t ) ) {
     180                        // will need more complicated checking if we want this to work with pointer types, since currently
     181                        return true;
     182                } else if ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) {
     183                        // an array's constructor, etc. is generated on the fly based on the base type's constructor, etc.
     184                        return lookup( map, at->get_base() );
     185                }
     186                TypeMap::const_iterator it = map.find( Mangler::mangleType( t ) );
     187                if ( it != map.end() ) return it->second;
     188                // something that does not appear in the map is by default not constructable, etc.
     189                return false;
     190        }
     191
     192        /// using map and aggr, examines each member to determine if constructor, etc. should be generated
     193        template<typename AggrDecl>
     194        bool shouldGenerate( const TypeMap & map, AggrDecl * aggr ) {
     195                for ( Declaration * dcl : aggr->get_members() ) {
     196                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( dcl ) ) {
     197                                if ( ! lookup( map, dwt->get_type() ) ) return false;
     198                        }
     199                }
     200                return true;
     201        }
     202
     203        /// data structure for abstracting the generation of special functions
     204        template< typename OutputIterator >
     205        struct FuncGenerator {
     206                StructDecl *aggregateDecl;
     207                StructInstType *refType;
     208                unsigned int functionNesting;
     209                const std::list< TypeDecl* > & typeParams;
     210                OutputIterator out;
     211                FuncGenerator( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, const std::list< TypeDecl* > & typeParams, OutputIterator out ) : aggregateDecl( aggregateDecl ), refType( refType ), functionNesting( functionNesting ), typeParams( typeParams ), out( out ) {}
     212
     213                /// generates a function (?{}, ?=?, ^?{}) based on the data argument and members. If function is generated, inserts the type into the map.
     214                void gen( const FuncData & data ) {
     215                        if ( ! shouldGenerate( data.map, aggregateDecl ) ) return;
     216                        FunctionType * ftype = data.genType( refType );
     217                        cloneAll( typeParams, ftype->get_forall() );
     218                        *out++ = genFunc( data.fname, ftype, functionNesting );
     219                        data.map.insert( Mangler::mangleType( refType ), true );
     220                }
     221        };
     222
     223        template< typename OutputIterator >
     224        FuncGenerator<OutputIterator> makeFuncGenerator( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, const std::list< TypeDecl* > & typeParams, OutputIterator out ) {
     225                return FuncGenerator<OutputIterator>( aggregateDecl, refType, functionNesting, typeParams, out );
    146226        }
    147227
     
    308388
    309389        /// generates struct constructors, destructor, and assignment functions
    310         void makeStructFunctions( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) {
    311 
     390        void makeStructFunctions( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd, const std::vector< FuncData > & data ) {
    312391                // Make function polymorphic in same parameters as generic struct, if applicable
    313392                const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions
    314393                bool isDynamicLayout = hasDynamicLayout( aggregateDecl );  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for union)
    315394
    316                 // T ?=?(T *, T);
    317                 FunctionType *assignType = genAssignType( refType );
    318                 cloneAll( typeParams, assignType->get_forall() );
    319 
    320                 // void ?{}(T *); void ^?{}(T *);
    321                 FunctionType *ctorType = genDefaultType( refType );
    322                 cloneAll( typeParams, ctorType->get_forall() );
    323                 FunctionType *dtorType = genDefaultType( refType );
    324                 cloneAll( typeParams, dtorType->get_forall() );
    325 
    326                 // void ?{}(T *, T);
    327                 FunctionType *copyCtorType = genCopyType( refType );
    328                 cloneAll( typeParams, copyCtorType->get_forall() );
    329 
    330                 FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting );
    331                 FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting );
    332                 FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting );
    333                 FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
     395                // generate each of the functions based on the supplied FuncData objects
     396                std::list< FunctionDecl * > newFuncs;
     397                auto generator = makeFuncGenerator( aggregateDecl, refType, functionNesting, typeParams, back_inserter( newFuncs ) );
     398                for ( const FuncData & d : data ) {
     399                        generator.gen( d );
     400                }
     401                // field ctors are only generated if default constructor and copy constructor are both generated
     402                unsigned numCtors = std::count_if( newFuncs.begin(), newFuncs.end(), [](FunctionDecl * dcl) { return InitTweak::isConstructor( dcl->get_name() ); } );
    334403
    335404                if ( functionNesting == 0 ) {
     
    338407                        // Note: this is necessary if we want structs which contain
    339408                        // generic (otype) structs as members.
    340                         addForwardDecl( assignDecl, declsToAdd );
    341                         addForwardDecl( ctorDecl, declsToAdd );
    342                         addForwardDecl( copyCtorDecl, declsToAdd );
    343                         addForwardDecl( dtorDecl, declsToAdd );
     409                        for ( FunctionDecl * dcl : newFuncs ) {
     410                                addForwardDecl( dcl, declsToAdd );
     411                        }
     412                }
     413
     414                for ( FunctionDecl * dcl : newFuncs ) {
     415                        // generate appropriate calls to member ctor, assignment
     416                        // destructor needs to do everything in reverse, so pass "forward" based on whether the function is a destructor
     417                        if ( ! InitTweak::isDestructor( dcl->get_name() ) ) {
     418                                makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), dcl, isDynamicLayout );
     419                        } else {
     420                                makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dcl, isDynamicLayout, false );
     421                        }
     422                        if ( InitTweak::isAssignment( dcl->get_name() ) ) {
     423                                // assignment needs to return a value
     424                                FunctionType * assignType = dcl->get_functionType();
     425                                assert( assignType->get_parameters().size() == 2 );
     426                                ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( assignType->get_parameters().back() );
     427                                dcl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
     428                        }
     429                        declsToAdd.push_back( dcl );
    344430                }
    345431
    346432                // create constructors which take each member type as a parameter.
    347433                // for example, for struct A { int x, y; }; generate
    348                 // void ?{}(A *, int) and void ?{}(A *, int, int)
    349                 std::list<Declaration *> memCtors;
    350                 FunctionType * memCtorType = ctorType->clone();
    351                 for ( std::list<Declaration *>::iterator i = aggregateDecl->get_members().begin(); i != aggregateDecl->get_members().end(); ++i ) {
    352                         DeclarationWithType * member = dynamic_cast<DeclarationWithType *>( *i );
    353                         assert( member );
    354                         if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( member ) ) ) {
    355                                 // don't make a function whose parameter is an unnamed bitfield
    356                                 continue;
    357                         } else if ( member->get_name() == "" ) {
    358                                 // don't assign to anonymous members
    359                                 // xxx - this is a temporary fix. Anonymous members tie into
    360                                 // our inheritance model. I think the correct way to handle this is to
    361                                 // cast the structure to the type of the member and let the resolver
    362                                 // figure out whether it's valid and have a pass afterwards that fixes
    363                                 // the assignment to use pointer arithmetic with the offset of the
    364                                 // member, much like how generic type members are handled.
    365                                 continue;
    366                         }
    367                         memCtorType->get_parameters().push_back( new ObjectDecl( member->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, member->get_type()->clone(), 0 ) );
    368                         FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
    369                         makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor, isDynamicLayout );
    370                         memCtors.push_back( ctor );
    371                 }
    372                 delete memCtorType;
    373 
    374                 // generate appropriate calls to member ctor, assignment
    375                 makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), assignDecl, isDynamicLayout );
    376                 makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctorDecl, isDynamicLayout );
    377                 makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), copyCtorDecl, isDynamicLayout );
    378                 // needs to do everything in reverse, so pass "forward" as false
    379                 makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dtorDecl, isDynamicLayout, false );
    380 
    381                 assert( assignType->get_parameters().size() == 2 );
    382                 ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( assignType->get_parameters().back() );
    383                 assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
    384 
    385                 declsToAdd.push_back( ctorDecl );
    386                 declsToAdd.push_back( copyCtorDecl );
    387                 declsToAdd.push_back( dtorDecl );
    388                 declsToAdd.push_back( assignDecl ); // assignment should come last since it uses copy constructor in return
    389                 declsToAdd.splice( declsToAdd.end(), memCtors );
     434                //   void ?{}(A *, int) and void ?{}(A *, int, int)
     435                // Field constructors are only generated if default and copy constructor
     436                // are generated, since they need access to both
     437                if ( numCtors == 2 ) {
     438                        FunctionType * memCtorType = genDefaultType( refType );
     439                        cloneAll( typeParams, memCtorType->get_forall() );
     440                        for ( std::list<Declaration *>::iterator i = aggregateDecl->get_members().begin(); i != aggregateDecl->get_members().end(); ++i ) {
     441                                DeclarationWithType * member = dynamic_cast<DeclarationWithType *>( *i );
     442                                assert( member );
     443                                if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( member ) ) ) {
     444                                        // don't make a function whose parameter is an unnamed bitfield
     445                                        continue;
     446                                } else if ( member->get_name() == "" ) {
     447                                        // don't assign to anonymous members
     448                                        // xxx - this is a temporary fix. Anonymous members tie into
     449                                        // our inheritance model. I think the correct way to handle this is to
     450                                        // cast the structure to the type of the member and let the resolver
     451                                        // figure out whether it's valid and have a pass afterwards that fixes
     452                                        // the assignment to use pointer arithmetic with the offset of the
     453                                        // member, much like how generic type members are handled.
     454                                        continue;
     455                                }
     456                                memCtorType->get_parameters().push_back( new ObjectDecl( member->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, member->get_type()->clone(), 0 ) );
     457                                FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
     458                                makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor, isDynamicLayout );
     459                                declsToAdd.push_back( ctor );
     460                        }
     461                        delete memCtorType;
     462                }
    390463        }
    391464
     
    481554        }
    482555
     556        AutogenerateRoutines::AutogenerateRoutines() {
     557                // the order here determines the order that these functions are generated.
     558                // assignment should come last since it uses copy constructor in return.
     559                data.push_back( FuncData( "?{}", genDefaultType, constructable ) );
     560                data.push_back( FuncData( "?{}", genCopyType, copyable ) );
     561                data.push_back( FuncData( "^?{}", genDefaultType, destructable ) );
     562                data.push_back( FuncData( "?=?", genAssignType, assignable ) );
     563        }
     564
    483565        void AutogenerateRoutines::visit( EnumDecl *enumDecl ) {
    484566                if ( ! enumDecl->get_members().empty() ) {
     
    491573
    492574        void AutogenerateRoutines::visit( StructDecl *structDecl ) {
    493                 if ( ! structDecl->get_members().empty() && structsDone.find( structDecl->get_name() ) == structsDone.end() ) {
     575                if ( structDecl->has_body() && structsDone.find( structDecl->get_name() ) == structsDone.end() ) {
    494576                        StructInstType structInst( Type::Qualifiers(), structDecl->get_name() );
    495577                        for ( TypeDecl * typeDecl : structDecl->get_parameters() ) {
     578                                // need to visit assertions so that they are added to the appropriate maps
     579                                acceptAll( typeDecl->get_assertions(), *this );
    496580                                structInst.get_parameters().push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), typeDecl ) ) );
    497581                        }
    498582                        structInst.set_baseStruct( structDecl );
    499                         makeStructFunctions( structDecl, &structInst, functionNesting, declsToAdd );
     583                        makeStructFunctions( structDecl, &structInst, functionNesting, declsToAdd, data );
    500584                        structsDone.insert( structDecl->get_name() );
    501585                } // if
     
    564648
    565649        void AutogenerateRoutines::visit( FunctionDecl *functionDecl ) {
     650                // record the existence of this function as appropriate
     651                insert( functionDecl, constructable, InitTweak::isDefaultConstructor );
     652                insert( functionDecl, assignable, InitTweak::isAssignment );
     653                insert( functionDecl, copyable, InitTweak::isCopyConstructor );
     654                insert( functionDecl, destructable, InitTweak::isDestructor );
     655
    566656                maybeAccept( functionDecl->get_functionType(), *this );
    567657                acceptAll( functionDecl->get_oldDecls(), *this );
     
    572662
    573663        void AutogenerateRoutines::visit( CompoundStmt *compoundStmt ) {
     664                constructable.beginScope();
     665                assignable.beginScope();
     666                copyable.beginScope();
     667                destructable.beginScope();
    574668                visitStatement( compoundStmt );
     669                constructable.endScope();
     670                assignable.endScope();
     671                copyable.endScope();
     672                destructable.endScope();
    575673        }
    576674
Note: See TracChangeset for help on using the changeset viewer.