Changeset 3da470c


Ignore:
Timestamp:
Apr 8, 2016, 5:23:19 PM (6 years ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, ctor, deferred_resn, demangler, gc_noraii, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, resolv-new, string, with_gc
Children:
9827c7ba
Parents:
630a82a (diff), 224e52f (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 branch 'master' of plg2:software/cfa/cfa-cc

Location:
src
Files:
1 added
18 edited

Legend:

Unmodified
Added
Removed
  • src/CodeGen/CodeGenerator.cc

    r630a82a r3da470c  
    455455
    456456        void CodeGenerator::visit( UntypedOffsetofExpr *offsetofExpr ) {
    457                 assert( false );
     457                assert( false && "UntypedOffsetofExpr should not reach code generation" );
    458458        }
    459459
     
    464464                output << ", " << mangleName( offsetofExpr->get_member() );
    465465                output << ")";
     466        }
     467
     468        void CodeGenerator::visit( OffsetPackExpr *offsetPackExpr ) {
     469                assert( false && "OffsetPackExpr should not reach code generation" );
    466470        }
    467471 
  • src/CodeGen/CodeGenerator.h

    r630a82a r3da470c  
    6565                virtual void visit( UntypedOffsetofExpr *offsetofExpr );
    6666                virtual void visit( OffsetofExpr *offsetofExpr );
     67                virtual void visit( OffsetPackExpr *offsetPackExpr );
    6768                virtual void visit( LogicalExpr *logicalExpr );
    6869                virtual void visit( ConditionalExpr *conditionalExpr );
  • src/GenPoly/Box.cc

    r630a82a r3da470c  
    3030#include "FindFunction.h"
    3131#include "ScopedMap.h"
     32#include "ScopedSet.h"
    3233#include "ScrubTyVars.h"
    3334
     
    6263                FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars );
    6364
    64                 /// Key for a unique concrete type; generic base type paired with type parameter list
    65                 struct ConcreteType {
    66                         ConcreteType() : base(NULL), params() {}
    67 
    68                         ConcreteType(AggregateDecl *_base, const std::list< Type* >& _params) : base(_base), params() { cloneAll(_params, params); }
    69 
    70                         ConcreteType(const ConcreteType& that) : base(that.base), params() { cloneAll(that.params, params); }
     65                /// Abstracts type equality for a list of parameter types
     66                struct TypeList {
     67                        TypeList() : params() {}
     68                        TypeList( const std::list< Type* > &_params ) : params() { cloneAll(_params, params); }
     69                        TypeList( std::list< Type* > &&_params ) : params( _params ) {}
     70
     71                        TypeList( const TypeList &that ) : params() { cloneAll(that.params, params); }
     72                        TypeList( TypeList &&that ) : params( std::move( that.params ) ) {}
    7173
    7274                        /// Extracts types from a list of TypeExpr*
    73                         ConcreteType(AggregateDecl *_base, const std::list< TypeExpr* >& _params) : base(_base), params() {
     75                        TypeList( const std::list< TypeExpr* >& _params ) : params() {
    7476                                for ( std::list< TypeExpr* >::const_iterator param = _params.begin(); param != _params.end(); ++param ) {
    7577                                        params.push_back( (*param)->get_type()->clone() );
     
    7779                        }
    7880
    79                         ConcreteType& operator= (const ConcreteType& that) {
     81                        TypeList& operator= ( const TypeList &that ) {
    8082                                deleteAll( params );
     83
    8184                                params.clear();
    82 
    83                                 base = that.base;
    8485                                cloneAll( that.params, params );
    8586
     
    8788                        }
    8889
    89                         ~ConcreteType() { deleteAll( params ); }
    90 
    91                         bool operator== (const ConcreteType& that) const {
    92                                 if ( base != that.base ) return false;
     90                        TypeList& operator= ( TypeList &&that ) {
     91                                deleteAll( params );
     92
     93                                params = std::move( that.params );
     94
     95                                return *this;
     96                        }
     97
     98                        ~TypeList() { deleteAll( params ); }
     99
     100                        bool operator== ( const TypeList& that ) const {
     101                                if ( params.size() != that.params.size() ) return false;
    93102
    94103                                SymTab::Indexer dummy;
    95                                 if ( params.size() != that.params.size() ) return false;
    96104                                for ( std::list< Type* >::const_iterator it = params.begin(), jt = that.params.begin(); it != params.end(); ++it, ++jt ) {
    97105                                        if ( ! ResolvExpr::typesCompatible( *it, *jt, dummy ) ) return false;
     
    100108                        }
    101109
    102                         AggregateDecl *base;        ///< Base generic type
    103110                        std::list< Type* > params;  ///< Instantiation parameters
    104111                };
    105112
    106                 /// Maps a concrete type to the some value, accounting for scope
    107                 template< typename Value >
     113                /// Maps a key and a TypeList to the some value, accounting for scope
     114                template< typename Key, typename Value >
    108115                class InstantiationMap {
    109                         /// Information about a specific instantiation of a generic type
    110                         struct Instantiation {
    111                                 ConcreteType key;  ///< Instantiation parameters for this type
    112                                 Value *value;      ///< Value for this instantiation
    113 
    114                                 Instantiation() : key(), value(0) {}
    115                                 Instantiation(const ConcreteType &_key, Value *_value) : key(_key), value(_value) {}
    116                         };
    117                         /// Map of generic types to instantiations of them
    118                         typedef std::map< AggregateDecl*, std::vector< Instantiation > > Scope;
    119 
    120                         std::vector< Scope > scopes;  ///< list of scopes, from outermost to innermost
     116                        /// Wraps value for a specific (Key, TypeList) combination
     117                        typedef std::pair< TypeList, Value* > Instantiation;
     118                        /// List of TypeLists paired with their appropriate values
     119                        typedef std::vector< Instantiation > ValueList;
     120                        /// Underlying map type; maps keys to a linear list of corresponding TypeLists and values
     121                        typedef ScopedMap< Key*, ValueList > InnerMap;
     122
     123                        InnerMap instantiations;  ///< instantiations
    121124
    122125                public:
    123126                        /// Starts a new scope
    124                         void beginScope() {
    125                                 Scope scope;
    126                                 scopes.push_back(scope);
    127                         }
     127                        void beginScope() { instantiations.beginScope(); }
    128128
    129129                        /// Ends a scope
    130                         void endScope() {
    131                                 scopes.pop_back();
    132                         }
    133 
    134                         /// Default constructor initializes with one scope
    135                         InstantiationMap() { beginScope(); }
    136 
    137 //              private:
    138                         /// Gets the value for the concrete instantiation of this type, assuming it has already been instantiated in the current scope.
    139                         /// Returns NULL on none such.
    140                         Value *lookup( AggregateDecl *generic, const std::list< TypeExpr* >& params ) {
    141                                 ConcreteType key(generic, params);
    142                                 // scan scopes from innermost out
    143                                 for ( typename std::vector< Scope >::const_reverse_iterator scope = scopes.rbegin(); scope != scopes.rend(); ++scope ) {
    144                                         // skip scope if no instantiations of this generic type
    145                                         typename Scope::const_iterator insts = scope->find( generic );
    146                                         if ( insts == scope->end() ) continue;
    147                                         // look through instantiations for matches to concrete type
    148                                         for ( typename std::vector< Instantiation >::const_iterator inst = insts->second.begin(); inst != insts->second.end(); ++inst ) {
    149                                                 if ( inst->key == key ) return inst->value;
     130                        void endScope() { instantiations.endScope(); }
     131
     132                        /// Gets the value for the (key, typeList) pair, returns NULL on none such.
     133                        Value *lookup( Key *key, const std::list< TypeExpr* >& params ) const {
     134                                TypeList typeList( params );
     135                               
     136                                // scan scopes for matches to the key
     137                                for ( typename InnerMap::const_iterator insts = instantiations.find( key ); insts != instantiations.end(); insts = instantiations.findNext( insts, key ) ) {
     138                                        for ( typename ValueList::const_reverse_iterator inst = insts->second.rbegin(); inst != insts->second.rend(); ++inst ) {
     139                                                if ( inst->first == typeList ) return inst->second;
    150140                                        }
    151141                                }
    152                                 // no matching instantiation found
     142                                // no matching instantiations found
    153143                                return 0;
    154144                        }
    155                 public:
    156 //                      StructDecl* lookup( StructInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (StructDecl*)lookup( inst->get_baseStruct(), typeSubs ); }
    157 //                      UnionDecl* lookup( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (UnionDecl*)lookup( inst->get_baseUnion(), typeSubs ); }
    158 
    159 //              private:
    160                         /// Adds a value for a concrete type to the current scope
    161                         void insert( AggregateDecl *generic, const std::list< TypeExpr* > &params, Value *value ) {
    162                                 ConcreteType key(generic, params);
    163                                 scopes.back()[generic].push_back( Instantiation( key, value ) );
    164                         }
    165 //              public:
    166 //                      void insert( StructInstType *inst, const std::list< TypeExpr* > &typeSubs, StructDecl *decl ) { insert( inst->get_baseStruct(), typeSubs, decl ); }
    167 //                      void insert( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs, UnionDecl *decl ) { insert( inst->get_baseUnion(), typeSubs, decl ); }
     145
     146                        /// Adds a value for a (key, typeList) pair to the current scope
     147                        void insert( Key *key, const std::list< TypeExpr* > &params, Value *value ) {
     148                                instantiations[ key ].push_back( Instantiation( TypeList( params ), value ) );
     149                        }
    168150                };
    169151
     
    197179                        virtual void doEndScope();
    198180                  private:
    199                         /// Makes a new temporary array holding the offsets of the fields of `type`, and returns a new variable expression referencing it
    200                         Expression *makeOffsetArray( StructInstType *type );
    201181                        /// Pass the extra type parameters from polymorphic generic arguments or return types into a function application
    202182                        void passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes );
     
    225205                        ObjectDecl *makeTemporary( Type *type );
    226206
    227                         std::map< std::string, DeclarationWithType *> assignOps;
    228                         ResolvExpr::TypeMap< DeclarationWithType > scopedAssignOps;
    229                         ScopedMap< std::string, DeclarationWithType* > adapters;
     207                        std::map< std::string, DeclarationWithType *> assignOps;     ///< Currently known type variable assignment operators
     208                        ResolvExpr::TypeMap< DeclarationWithType > scopedAssignOps;  ///< Currently known assignment operators
     209                        ScopedMap< std::string, DeclarationWithType* > adapters;     ///< Set of adapter functions in the current scope
     210                       
    230211                        DeclarationWithType *retval;
    231212                        bool useRetval;
     
    233214                };
    234215
    235                 /// Moves polymorphic returns in function types to pointer-type parameters, adds type size and assertion parameters to parameter lists as well
     216                /// * Moves polymorphic returns in function types to pointer-type parameters
     217                /// * adds type size and assertion parameters to parameter lists
    236218                class Pass2 : public PolyMutator {
    237219                  public:
     
    244226                        virtual Type *mutate( PointerType *pointerType );
    245227                        virtual Type *mutate( FunctionType *funcType );
     228                       
    246229                  private:
    247230                        void addAdapters( FunctionType *functionType );
     
    253236                class GenericInstantiator : public DeclMutator {
    254237                        /// Map of (generic type, parameter list) pairs to concrete type instantiations
    255                         InstantiationMap< AggregateDecl > instantiations;
     238                        InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
    256239                        /// Namer for concrete types
    257240                        UniqueName typeNamer;
     
    278261                };
    279262
    280                 /// Replaces member expressions for polymorphic types with calculated add-field-offset-and-dereference;
    281                 /// also fixes offsetof expressions.
    282                 class MemberExprFixer : public PolyMutator {
    283                   public:
     263                /// Replaces member and size/align/offsetof expressions on polymorphic generic types with calculated expressions.
     264                /// * Replaces member expressions for polymorphic types with calculated add-field-offset-and-dereference
     265                /// * Calculates polymorphic offsetof expressions from offset array
     266                /// * Inserts dynamic calculation of polymorphic type layouts where needed
     267                class PolyGenericCalculator : public PolyMutator {
     268                public:
    284269                        template< typename DeclClass >
    285270                        DeclClass *handleDecl( DeclClass *decl, Type *type );
     
    292277                        virtual Type *mutate( FunctionType *funcType );
    293278                        virtual Expression *mutate( MemberExpr *memberExpr );
     279                        virtual Expression *mutate( SizeofExpr *sizeofExpr );
     280                        virtual Expression *mutate( AlignofExpr *alignofExpr );
    294281                        virtual Expression *mutate( OffsetofExpr *offsetofExpr );
     282                        virtual Expression *mutate( OffsetPackExpr *offsetPackExpr );
     283
     284                        virtual void doBeginScope();
     285                        virtual void doEndScope();
     286
     287                private:
     288                        /// Makes a new variable in the current scope with the given name, type & optional initializer
     289                        ObjectDecl *makeVar( const std::string &name, Type *type, Initializer *init = 0 );
     290                        /// returns true if the type has a dynamic layout; such a layout will be stored in appropriately-named local variables when the function returns
     291                        bool findGeneric( Type *ty );
     292                        /// adds type parameters to the layout call; will generate the appropriate parameters if needed
     293                        void addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams );
     294                       
     295                        ScopedSet< std::string > knownLayouts;          ///< Set of generic type layouts known in the current scope, indexed by sizeofName
     296                        ScopedSet< std::string > knownOffsets;          ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName
    295297                };
    296298
     
    342344                Pass2 pass2;
    343345                GenericInstantiator instantiator;
    344                 MemberExprFixer memberFixer;
     346                PolyGenericCalculator polyCalculator;
    345347                Pass3 pass3;
    346348               
     
    348350                mutateTranslationUnit/*All*/( translationUnit, pass1 );
    349351                mutateTranslationUnit/*All*/( translationUnit, pass2 );
    350 //              instantiateGeneric( translationUnit );
    351352                instantiator.mutateDeclarationList( translationUnit );
    352                 mutateTranslationUnit/*All*/( translationUnit, memberFixer );
     353                mutateTranslationUnit/*All*/( translationUnit, polyCalculator );
    353354                mutateTranslationUnit/*All*/( translationUnit, pass3 );
    354355        }
     
    653654
    654655                DeclarationWithType *Pass1::mutate( FunctionDecl *functionDecl ) {
    655                         // if this is a polymorphic assignment function, put it in the map for this scope
     656                        // if this is a assignment function, put it in the map for this scope
    656657                        if ( Type *assignedType = isAssignment( functionDecl ) ) {
    657658                                if ( ! dynamic_cast< TypeInstType* >( assignedType ) ) {
     
    743744                }
    744745
    745                 Expression *Pass1::makeOffsetArray( StructInstType *ty ) {
    746                         std::list< Declaration* > &baseMembers = ty->get_baseStruct()->get_members();
    747 
    748                         // make a new temporary array
    749                         Type *offsetType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
    750                         std::stringstream lenGen;
    751                         lenGen << baseMembers.size();
    752                         ConstantExpr *lenExpr = new ConstantExpr( Constant( offsetType->clone(), lenGen.str() ) );
    753                         ObjectDecl *arrayTemp = makeTemporary( new ArrayType( Type::Qualifiers(), offsetType, lenExpr, false, false ) );
    754 
    755                         // build initializer list for temporary
    756                         std::list< Initializer* > inits;
    757                         for ( std::list< Declaration* >::const_iterator member = baseMembers.begin(); member != baseMembers.end(); ++member ) {
    758                                 DeclarationWithType *memberDecl;
    759                                 if ( DeclarationWithType *origMember = dynamic_cast< DeclarationWithType* >( *member ) ) {
    760                                         memberDecl = origMember->clone();
    761                                 } else {
    762                                         memberDecl = new ObjectDecl( (*member)->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, offsetType->clone(), 0 );
    763                                 }
    764                                 inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
    765                         }
    766                         arrayTemp->set_init( new ListInit( inits ) );
    767 
    768                         // return variable pointing to temporary
    769                         return new VariableExpr( arrayTemp );
    770                 }
    771 
    772746                void Pass1::passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes ) {
    773747                        Type *polyBase = hasPolyBase( parmType, exprTyVars );
     
    782756                                if ( dynamic_cast< StructInstType* >( polyBase ) ) {
    783757                                        if ( StructInstType *argBaseStructType = dynamic_cast< StructInstType* >( argBaseType ) ) {
    784                                                 arg = appExpr->get_args().insert( arg, makeOffsetArray( argBaseStructType ) );
    785                                                 arg++;
     758                                                // zero-length arrays are forbidden by C, so don't pass offset for empty struct
     759                                                if ( ! argBaseStructType->get_baseStruct()->get_members().empty() ) {
     760                                                        arg = appExpr->get_args().insert( arg, new OffsetPackExpr( argBaseStructType->clone() ) );
     761                                                        arg++;
     762                                                }
    786763                                        } else {
    787764                                                throw SemanticError( "Cannot pass non-struct type for generic struct" );
     
    931908                                        return;
    932909                                } else if ( arg->get_results().front()->get_isLvalue() ) {
    933                                         // VariableExpr and MemberExpr are lvalues
    934                                         arg = new AddressExpr( arg );
     910                                        // VariableExpr and MemberExpr are lvalues; need to check this isn't coming from the second arg of a comma expression though (not an lvalue)
     911                                        if ( CommaExpr *commaArg = dynamic_cast< CommaExpr* >( arg ) ) {
     912                                                commaArg->set_arg2( new AddressExpr( commaArg->get_arg2() ) );
     913                                        } else {
     914                                                arg = new AddressExpr( arg );
     915                                        }
    935916                                } else {
    936917                                        // use type computed in unification to declare boxed variables
     
    10271008                        } // for
    10281009                }
    1029 
    1030 
    10311010
    10321011                FunctionDecl *Pass1::makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars ) {
     
    14281407                                        std::list< TypeDecl* >::const_iterator forallIt = forallParams.begin();
    14291408                                        for ( ; tyIt != tyParams.end() && forallIt != forallParams.end(); ++tyIt, ++forallIt ) {
    1430                                                 if ( (*forallIt)->get_kind() != TypeDecl::Any ) continue; // skip types with no assign op (ftype/dtype)
    1431 
    1432                                                 std::list< DeclarationWithType* > &asserts = (*forallIt)->get_assertions();
    1433                                                 assert( ! asserts.empty() && "Type param needs assignment operator assertion" );
    1434                                                 DeclarationWithType *actualDecl = asserts.front();
    1435                                                 TypeInstType *actualType = isTypeInstAssignment( actualDecl );
    1436                                                 assert( actualType && "First assertion of type with assertions should be assignment operator" );
     1409                                                // Add appropriate mapping to assignment expression environment
    14371410                                                TypeExpr *formalTypeExpr = dynamic_cast< TypeExpr* >( *tyIt );
    14381411                                                assert( formalTypeExpr && "type parameters must be type expressions" );
    14391412                                                Type *formalType = formalTypeExpr->get_type();
    1440                                                 assignExpr->get_env()->add( actualType->get_name(), formalType );
    1441                                                
     1413                                                assignExpr->get_env()->add( (*forallIt)->get_name(), formalType );
     1414
     1415                                                // skip types with no assign op (ftype/dtype)
     1416                                                if ( (*forallIt)->get_kind() != TypeDecl::Any ) continue;
     1417
     1418                                                // find assignment operator for formal type
    14421419                                                DeclarationWithType *assertAssign = 0;
    14431420                                                if ( TypeInstType *formalTypeInstType = dynamic_cast< TypeInstType* >( formalType ) ) {
     
    14531430                                                        }
    14541431                                                }
    1455                                                
    1456 
     1432
     1433                                                // add inferred parameter for field assignment operator to assignment expression
     1434                                                std::list< DeclarationWithType* > &asserts = (*forallIt)->get_assertions();
     1435                                                assert( ! asserts.empty() && "Type param needs assignment operator assertion" );
     1436                                                DeclarationWithType *actualDecl = asserts.front();
    14571437                                                assignExpr->get_inferParams()[ actualDecl->get_uniqueId() ]
    14581438                                                        = ParamEntry( assertAssign->get_uniqueId(), assertAssign->get_type()->clone(), actualDecl->get_type()->clone(), wrapFunctionDecl( assertAssign ) );
     
    15871567                        ObjectDecl newPtr( "", DeclarationNode::NoStorageClass, LinkageSpec::C, 0,
    15881568                                           new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 );
    1589 //   ObjectDecl *newFunPtr = new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) ), 0 );
    15901569                        for ( std::list< TypeDecl *>::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) {
    15911570                                ObjectDecl *sizeParm, *alignParm;
     
    16311610                                        ++last;
    16321611
    1633                                         if ( dynamic_cast< StructInstType* >( polyBase ) ) {
    1634                                                 offsetParm = newPtr.clone();
    1635                                                 offsetParm->set_name( offsetofName( polyBase ) );
    1636                                                 last = funcType->get_parameters().insert( last, offsetParm );
    1637                                                 ++last;
     1612                                        if ( StructInstType *polyBaseStruct = dynamic_cast< StructInstType* >( polyBase ) ) {
     1613                                                // NOTE zero-length arrays are illegal in C, so empty structs have no offset array
     1614                                                if ( ! polyBaseStruct->get_baseStruct()->get_members().empty() ) {
     1615                                                        offsetParm = newPtr.clone();
     1616                                                        offsetParm->set_name( offsetofName( polyBase ) );
     1617                                                        last = funcType->get_parameters().insert( last, offsetParm );
     1618                                                        ++last;
     1619                                                }
    16381620                                        }
    16391621
     
    18441826
    18451827                template< typename DeclClass >
    1846                 DeclClass * MemberExprFixer::handleDecl( DeclClass *decl, Type *type ) {
     1828                DeclClass * PolyGenericCalculator::handleDecl( DeclClass *decl, Type *type ) {
    18471829                        TyVarMap oldtyVars = scopeTyVars;
    18481830                        makeTyVarMap( type, scopeTyVars );
     
    18541836                }
    18551837
    1856                 ObjectDecl * MemberExprFixer::mutate( ObjectDecl *objectDecl ) {
     1838                ObjectDecl * PolyGenericCalculator::mutate( ObjectDecl *objectDecl ) {
    18571839                        return handleDecl( objectDecl, objectDecl->get_type() );
    18581840                }
    18591841
    1860                 DeclarationWithType * MemberExprFixer::mutate( FunctionDecl *functionDecl ) {
     1842                DeclarationWithType * PolyGenericCalculator::mutate( FunctionDecl *functionDecl ) {
    18611843                        return handleDecl( functionDecl, functionDecl->get_functionType() );
    18621844                }
    18631845
    1864                 TypedefDecl * MemberExprFixer::mutate( TypedefDecl *typedefDecl ) {
     1846                TypedefDecl * PolyGenericCalculator::mutate( TypedefDecl *typedefDecl ) {
    18651847                        return handleDecl( typedefDecl, typedefDecl->get_base() );
    18661848                }
    18671849
    1868                 TypeDecl * MemberExprFixer::mutate( TypeDecl *typeDecl ) {
     1850                TypeDecl * PolyGenericCalculator::mutate( TypeDecl *typeDecl ) {
    18691851                        scopeTyVars[ typeDecl->get_name() ] = typeDecl->get_kind();
    18701852                        return Mutator::mutate( typeDecl );
    18711853                }
    18721854
    1873                 Type * MemberExprFixer::mutate( PointerType *pointerType ) {
     1855                Type * PolyGenericCalculator::mutate( PointerType *pointerType ) {
    18741856                        TyVarMap oldtyVars = scopeTyVars;
    18751857                        makeTyVarMap( pointerType, scopeTyVars );
     
    18811863                }
    18821864
    1883                 Type * MemberExprFixer::mutate( FunctionType *functionType ) {
     1865                Type * PolyGenericCalculator::mutate( FunctionType *funcType ) {
    18841866                        TyVarMap oldtyVars = scopeTyVars;
    1885                         makeTyVarMap( functionType, scopeTyVars );
    1886 
    1887                         Type *ret = Mutator::mutate( functionType );
     1867                        makeTyVarMap( funcType, scopeTyVars );
     1868
     1869                        // make sure that any type information passed into the function is accounted for
     1870                        for ( std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin(); fnParm != funcType->get_parameters().end(); ++fnParm ) {
     1871                                // condition here duplicates that in Pass2::mutate( FunctionType* )
     1872                                Type *polyBase = hasPolyBase( (*fnParm)->get_type(), scopeTyVars );
     1873                                if ( polyBase && ! dynamic_cast< TypeInstType* >( polyBase ) ) {
     1874                                        knownLayouts.insert( sizeofName( polyBase ) );
     1875                                }
     1876                        }
     1877                       
     1878                        Type *ret = Mutator::mutate( funcType );
    18881879
    18891880                        scopeTyVars = oldtyVars;
     
    18911882                }
    18921883
    1893                 Statement *MemberExprFixer::mutate( DeclStmt *declStmt ) {
     1884                Statement *PolyGenericCalculator::mutate( DeclStmt *declStmt ) {
    18941885                        if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
    1895                                 if ( isPolyType( objectDecl->get_type(), scopeTyVars ) ) {
     1886                                if ( findGeneric( objectDecl->get_type() ) ) {
    18961887                                        // change initialization of a polymorphic value object
    18971888                                        // to allocate storage with alloca
     
    19451936                }
    19461937               
    1947                 Expression *MemberExprFixer::mutate( MemberExpr *memberExpr ) {
     1938                Expression *PolyGenericCalculator::mutate( MemberExpr *memberExpr ) {
    19481939                        // mutate, exiting early if no longer MemberExpr
    19491940                        Expression *expr = Mutator::mutate( memberExpr );
     
    19621953                        Type *objectType = hasPolyBase( objectDecl->get_type(), scopeTyVars, &tyDepth );
    19631954                        if ( ! objectType ) return memberExpr;
     1955                        findGeneric( objectType ); // ensure layout for this type is available
    19641956
    19651957                        Expression *newMemberExpr = 0;
     
    19931985                }
    19941986
    1995                 Expression *MemberExprFixer::mutate( OffsetofExpr *offsetofExpr ) {
     1987                ObjectDecl *PolyGenericCalculator::makeVar( const std::string &name, Type *type, Initializer *init ) {
     1988                        ObjectDecl *newObj = new ObjectDecl( name, DeclarationNode::NoStorageClass, LinkageSpec::C, 0, type, init );
     1989                        stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) );
     1990                        return newObj;
     1991                }
     1992
     1993                void PolyGenericCalculator::addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ) {
     1994                        for ( std::list< Type* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param ) {
     1995                                if ( findGeneric( *param ) ) {
     1996                                        // push size/align vars for a generic parameter back
     1997                                        layoutCall->get_args().push_back( new NameExpr( sizeofName( *param ) ) );
     1998                                        layoutCall->get_args().push_back( new NameExpr( alignofName( *param ) ) );
     1999                                } else {
     2000                                        layoutCall->get_args().push_back( new SizeofExpr( (*param)->clone() ) );
     2001                                        layoutCall->get_args().push_back( new AlignofExpr( (*param)->clone() ) );
     2002                                }
     2003                        }
     2004                }
     2005
     2006                /// returns true if any of the otype parameters have a dynamic layout and puts all otype parameters in the output list
     2007                bool findGenericParams( std::list< TypeDecl* > &baseParams, std::list< Expression* > &typeParams, std::list< Type* > &out ) {
     2008                        bool hasDynamicLayout = false;
     2009
     2010                        std::list< TypeDecl* >::const_iterator baseParam = baseParams.begin();
     2011                        std::list< Expression* >::const_iterator typeParam = typeParams.begin();
     2012                        for ( ; baseParam != baseParams.end() && typeParam != typeParams.end(); ++baseParam, ++typeParam ) {
     2013                                // skip non-otype parameters
     2014                                if ( (*baseParam)->get_kind() != TypeDecl::Any ) continue;
     2015                                TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( *typeParam );
     2016                                assert( typeExpr && "all otype parameters should be type expressions" );
     2017
     2018                                Type *type = typeExpr->get_type();
     2019                                out.push_back( type );
     2020                                if ( isPolyType( type ) ) hasDynamicLayout = true;
     2021                        }
     2022                        assert( baseParam == baseParams.end() && typeParam == typeParams.end() );
     2023
     2024                        return hasDynamicLayout;
     2025                }
     2026
     2027                bool PolyGenericCalculator::findGeneric( Type *ty ) {
     2028                        if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( ty ) ) {
     2029                                // duplicate logic from isPolyType()
     2030                                if ( env ) {
     2031                                        if ( Type *newType = env->lookup( typeInst->get_name() ) ) {
     2032                                                return findGeneric( newType );
     2033                                        } // if
     2034                                } // if
     2035                                if ( scopeTyVars.find( typeInst->get_name() ) != scopeTyVars.end() ) {
     2036                                        // NOTE assumes here that getting put in the scopeTyVars included having the layout variables set
     2037                                        return true;
     2038                                }
     2039                                return false;
     2040                        } else if ( StructInstType *structTy = dynamic_cast< StructInstType* >( ty ) ) {
     2041                                // check if this type already has a layout generated for it
     2042                                std::string sizeName = sizeofName( ty );
     2043                                if ( knownLayouts.find( sizeName ) != knownLayouts.end() ) return true;
     2044
     2045                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
     2046                                std::list< Type* > otypeParams;
     2047                                if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->get_parameters(), otypeParams ) ) return false;
     2048
     2049                                // insert local variables for layout and generate call to layout function
     2050                                knownLayouts.insert( sizeName );  // done early so as not to interfere with the later addition of parameters to the layout call
     2051                                Type *layoutType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
     2052
     2053                                int n_members = structTy->get_baseStruct()->get_members().size();
     2054                                if ( n_members == 0 ) {
     2055                                        // all empty structs have the same layout - size 1, align 1
     2056                                        makeVar( sizeName, layoutType, new SingleInit( new ConstantExpr( Constant::from( (unsigned long)1 ) ) ) );
     2057                                        makeVar( alignofName( ty ), layoutType->clone(), new SingleInit( new ConstantExpr( Constant::from( (unsigned long)1 ) ) ) );
     2058                                        // NOTE zero-length arrays are forbidden in C, so empty structs have no offsetof array
     2059                                } else {
     2060                                        ObjectDecl *sizeVar = makeVar( sizeName, layoutType );
     2061                                        ObjectDecl *alignVar = makeVar( alignofName( ty ), layoutType->clone() );
     2062                                        ObjectDecl *offsetVar = makeVar( offsetofName( ty ), new ArrayType( Type::Qualifiers(), layoutType->clone(), new ConstantExpr( Constant::from( n_members ) ), false, false ) );
     2063
     2064                                        // generate call to layout function
     2065                                        UntypedExpr *layoutCall = new UntypedExpr( new NameExpr( "__layoutof_" + structTy->get_baseStruct()->get_name() ) );
     2066                                        layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( sizeVar ) ) );
     2067                                        layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( alignVar ) ) );
     2068                                        layoutCall->get_args().push_back( new VariableExpr( offsetVar ) );
     2069                                        addOtypeParamsToLayoutCall( layoutCall, otypeParams );
     2070
     2071                                        stmtsToAdd.push_back( new ExprStmt( noLabels, layoutCall ) );
     2072                                }
     2073
     2074                                return true;
     2075                        } else if ( UnionInstType *unionTy = dynamic_cast< UnionInstType* >( ty ) ) {
     2076                                // check if this type already has a layout generated for it
     2077                                std::string sizeName = sizeofName( ty );
     2078                                if ( knownLayouts.find( sizeName ) != knownLayouts.end() ) return true;
     2079
     2080                                // check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
     2081                                std::list< Type* > otypeParams;
     2082                                if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->get_parameters(), otypeParams ) ) return false;
     2083
     2084                                // insert local variables for layout and generate call to layout function
     2085                                knownLayouts.insert( sizeName );  // done early so as not to interfere with the later addition of parameters to the layout call
     2086                                Type *layoutType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
     2087
     2088                                ObjectDecl *sizeVar = makeVar( sizeName, layoutType );
     2089                                ObjectDecl *alignVar = makeVar( alignofName( ty ), layoutType->clone() );
     2090
     2091                                // generate call to layout function
     2092                                UntypedExpr *layoutCall = new UntypedExpr( new NameExpr( "__layoutof_" + unionTy->get_baseUnion()->get_name() ) );
     2093                                layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( sizeVar ) ) );
     2094                                layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( alignVar ) ) );
     2095                                addOtypeParamsToLayoutCall( layoutCall, otypeParams );
     2096
     2097                                stmtsToAdd.push_back( new ExprStmt( noLabels, layoutCall ) );
     2098
     2099                                return true;
     2100                        }
     2101
     2102                        return false;
     2103                }
     2104
     2105                Expression *PolyGenericCalculator::mutate( SizeofExpr *sizeofExpr ) {
     2106                        Type *ty = sizeofExpr->get_type();
     2107                        if ( findGeneric( ty ) ) {
     2108                                Expression *ret = new NameExpr( sizeofName( ty ) );
     2109                                delete sizeofExpr;
     2110                                return ret;
     2111                        }
     2112                        return sizeofExpr;
     2113                }
     2114
     2115                Expression *PolyGenericCalculator::mutate( AlignofExpr *alignofExpr ) {
     2116                        Type *ty = alignofExpr->get_type();
     2117                        if ( findGeneric( ty ) ) {
     2118                                Expression *ret = new NameExpr( alignofName( ty ) );
     2119                                delete alignofExpr;
     2120                                return ret;
     2121                        }
     2122                        return alignofExpr;
     2123                }
     2124
     2125                Expression *PolyGenericCalculator::mutate( OffsetofExpr *offsetofExpr ) {
    19962126                        // mutate, exiting early if no longer OffsetofExpr
    19972127                        Expression *expr = Mutator::mutate( offsetofExpr );
     
    20002130
    20012131                        // only mutate expressions for polymorphic structs/unions
    2002                         Type *ty = isPolyType( offsetofExpr->get_type(), scopeTyVars );
    2003                         if ( ! ty ) return offsetofExpr;
    2004 
     2132                        Type *ty = offsetofExpr->get_type();
     2133                        if ( ! findGeneric( ty ) ) return offsetofExpr;
     2134                       
    20052135                        if ( StructInstType *structType = dynamic_cast< StructInstType* >( ty ) ) {
    20062136                                // replace offsetof expression by index into offset array
     
    20182148                }
    20192149
     2150                Expression *PolyGenericCalculator::mutate( OffsetPackExpr *offsetPackExpr ) {
     2151                        StructInstType *ty = offsetPackExpr->get_type();
     2152
     2153                        Expression *ret = 0;
     2154                        if ( findGeneric( ty ) ) {
     2155                                // pull offset back from generated type information
     2156                                ret = new NameExpr( offsetofName( ty ) );
     2157                        } else {
     2158                                std::string offsetName = offsetofName( ty );
     2159                                if ( knownOffsets.find( offsetName ) != knownOffsets.end() ) {
     2160                                        // use the already-generated offsets for this type
     2161                                        ret = new NameExpr( offsetName );
     2162                                } else {
     2163                                        knownOffsets.insert( offsetName );
     2164
     2165                                        std::list< Declaration* > &baseMembers = ty->get_baseStruct()->get_members();
     2166                                        Type *offsetType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
     2167
     2168                                        // build initializer list for offset array
     2169                                        std::list< Initializer* > inits;
     2170                                        for ( std::list< Declaration* >::const_iterator member = baseMembers.begin(); member != baseMembers.end(); ++member ) {
     2171                                                DeclarationWithType *memberDecl;
     2172                                                if ( DeclarationWithType *origMember = dynamic_cast< DeclarationWithType* >( *member ) ) {
     2173                                                        memberDecl = origMember->clone();
     2174                                                } else {
     2175                                                        memberDecl = new ObjectDecl( (*member)->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, offsetType->clone(), 0 );
     2176                                                }
     2177                                                inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
     2178                                        }
     2179
     2180                                        // build the offset array and replace the pack with a reference to it
     2181                                        ObjectDecl *offsetArray = makeVar( offsetName, new ArrayType( Type::Qualifiers(), offsetType, new ConstantExpr( Constant::from( baseMembers.size() ) ), false, false ),
     2182                                                        new ListInit( inits ) );
     2183                                        ret = new VariableExpr( offsetArray );
     2184                                }
     2185                        }
     2186
     2187                        delete offsetPackExpr;
     2188                        return ret;
     2189                }
     2190
     2191                void PolyGenericCalculator::doBeginScope() {
     2192                        knownLayouts.beginScope();
     2193                        knownOffsets.beginScope();
     2194                }
     2195
     2196                void PolyGenericCalculator::doEndScope() {
     2197                        knownLayouts.endScope();
     2198                        knownOffsets.beginScope();
     2199                }
     2200
    20202201////////////////////////////////////////// Pass3 ////////////////////////////////////////////////////
    20212202
  • src/GenPoly/ScopedMap.h

    r630a82a r3da470c  
    1717#define _SCOPEDMAP_H
    1818
     19#include <cassert>
    1920#include <iterator>
    2021#include <map>
     
    164165                void endScope() {
    165166                        scopes.pop_back();
     167                        assert( ! scopes.empty() );
    166168                }
    167169
     
    188190                        return end();
    189191                }
    190                 const_iterator find( const Key &key ) const { return const_iterator( find( key ) ); }
     192                const_iterator find( const Key &key ) const {
     193                                return const_iterator( const_cast< ScopedMap< Key, Value >* >(this)->find( key ) );
     194                }
    191195               
    192196                /// Finds the given key in the outermost scope inside the given scope where it occurs
     
    200204                        return end();
    201205                }
    202                 const_iterator findNext( const_iterator &it, const Key &key ) const { return const_iterator( findNext( it, key ) ); }
     206                const_iterator findNext( const_iterator &it, const Key &key ) const {
     207                                return const_iterator( const_cast< ScopedMap< Key, Value >* >(this)->findNext( it, key ) );
     208                }
    203209
    204210                /// Inserts the given key-value pair into the outermost scope
     
    208214                }
    209215                std::pair< iterator, bool > insert( const Key &key, const Value &value ) { return insert( std::make_pair( key, value ) ); }
    210                
     216
     217                Value& operator[] ( const Key &key ) {
     218                        iterator slot = find( key );
     219                        if ( slot != end() ) return slot->second;
     220                        return insert( key, Value() ).first->second;
     221                }
    211222        };
    212223} // namespace GenPoly
  • src/InitTweak/InitModel.h

    r630a82a r3da470c  
    7575                        void visit( UntypedOffsetofExpr * ) { throw 0; }
    7676                        void visit( OffsetofExpr * ) { throw 0; }
     77                        void visit( OffsetPackExpr * ) { throw 0; }
    7778                        void visit( AttrExpr * ) { throw 0; }
    7879                        void visit( LogicalExpr * ) { throw 0; }
  • src/ResolvExpr/AlternativeFinder.cc

    r630a82a r3da470c  
    848848        }
    849849
     850        void AlternativeFinder::visit( OffsetPackExpr *offsetPackExpr ) {
     851                alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
     852        }
     853
    850854        void AlternativeFinder::resolveAttr( DeclarationWithType *funcDecl, FunctionType *function, Type *argType, const TypeEnvironment &env ) {
    851855                // assume no polymorphism
  • src/ResolvExpr/AlternativeFinder.h

    r630a82a r3da470c  
    5959                virtual void visit( UntypedOffsetofExpr *offsetofExpr );
    6060                virtual void visit( OffsetofExpr *offsetofExpr );
     61                virtual void visit( OffsetPackExpr *offsetPackExpr );
    6162                virtual void visit( AttrExpr *attrExpr );
    6263                virtual void visit( LogicalExpr *logicalExpr );
  • src/SymTab/Indexer.cc

    r630a82a r3da470c  
    344344                maybeAccept( offsetofExpr->get_type(), *this );
    345345                maybeAccept( offsetofExpr->get_member(), *this );
     346        }
     347
     348        void Indexer::visit( OffsetPackExpr *offsetPackExpr ) {
     349                acceptAllNewScope( offsetPackExpr->get_results(), *this );
     350                maybeAccept( offsetPackExpr->get_type(), *this );
    346351        }
    347352
  • src/SymTab/Indexer.h

    r630a82a r3da470c  
    5959                virtual void visit( UntypedOffsetofExpr *offsetofExpr );
    6060                virtual void visit( OffsetofExpr *offsetofExpr );
     61                virtual void visit( OffsetPackExpr *offsetPackExpr );
    6162                virtual void visit( AttrExpr *attrExpr );
    6263                virtual void visit( LogicalExpr *logicalExpr );
  • src/SynTree/Expression.cc

    r630a82a r3da470c  
    223223}
    224224
     225OffsetPackExpr::OffsetPackExpr( StructInstType *type_, Expression *aname_ ) : Expression( aname_ ), type( type_ ) {
     226        add_result( new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0, false, false ) );
     227}
     228
     229OffsetPackExpr::OffsetPackExpr( const OffsetPackExpr &other ) : Expression( other ), type( maybeClone( other.type ) ) {}
     230
     231OffsetPackExpr::~OffsetPackExpr() { delete type; }
     232
     233void OffsetPackExpr::print( std::ostream &os, int indent ) const {
     234        os << std::string( indent, ' ' ) << "Offset pack expression on ";
     235
     236        if ( type ) {
     237                type->print(os, indent + 2);
     238        } else {
     239                os << "<NULL>";
     240        }
     241
     242        os << std::endl;
     243        Expression::print( os, indent );
     244}
     245
    225246AttrExpr::AttrExpr( Expression *attr, Expression *expr_, Expression *_aname ) :
    226247                Expression( _aname ), attr( attr ), expr(expr_), type(0), isType(false) {
  • src/SynTree/Expression.h

    r630a82a r3da470c  
    362362};
    363363
     364/// Expression representing a pack of field-offsets for a generic type
     365class OffsetPackExpr : public Expression {
     366public:
     367        OffsetPackExpr( StructInstType *type_, Expression *aname_ = 0 );
     368        OffsetPackExpr( const OffsetPackExpr &other );
     369        virtual ~OffsetPackExpr();
     370
     371        StructInstType *get_type() const { return type; }
     372        void set_type( StructInstType *newValue ) { type = newValue; }
     373
     374        virtual OffsetPackExpr *clone() const { return new OffsetPackExpr( *this ); }
     375        virtual void accept( Visitor &v ) { v.visit( this ); }
     376        virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
     377
     378        virtual void print( std::ostream &os, int indent = 0 ) const;
     379
     380private:
     381        StructInstType *type;
     382};
     383
    364384/// AttrExpr represents an @attribute expression (like sizeof, but user-defined)
    365385class AttrExpr : public Expression {
  • src/SynTree/Mutator.cc

    r630a82a r3da470c  
    274274}
    275275
     276Expression *Mutator::mutate( OffsetPackExpr *offsetPackExpr ) {
     277        mutateAll( offsetPackExpr->get_results(), *this );
     278        offsetPackExpr->set_type( maybeMutate( offsetPackExpr->get_type(), *this ) );
     279        return offsetPackExpr;
     280}
     281
    276282Expression *Mutator::mutate( AttrExpr *attrExpr ) {
    277283        mutateAll( attrExpr->get_results(), *this );
  • src/SynTree/Mutator.h

    r630a82a r3da470c  
    6767        virtual Expression* mutate( UntypedOffsetofExpr *offsetofExpr );
    6868        virtual Expression* mutate( OffsetofExpr *offsetofExpr );
     69        virtual Expression* mutate( OffsetPackExpr *offsetPackExpr );
    6970        virtual Expression* mutate( AttrExpr *attrExpr );
    7071        virtual Expression* mutate( LogicalExpr *logicalExpr );
  • src/SynTree/SynTree.h

    r630a82a r3da470c  
    7272class UntypedOffsetofExpr;
    7373class OffsetofExpr;
     74class OffsetPackExpr;
    7475class AttrExpr;
    7576class LogicalExpr;
  • src/SynTree/Visitor.cc

    r630a82a r3da470c  
    230230}
    231231
     232void Visitor::visit( OffsetPackExpr *offsetPackExpr ) {
     233        acceptAll( offsetPackExpr->get_results(), *this );
     234        maybeAccept( offsetPackExpr->get_type(), *this );
     235}
     236
    232237void Visitor::visit( AttrExpr *attrExpr ) {
    233238        acceptAll( attrExpr->get_results(), *this );
  • src/SynTree/Visitor.h

    r630a82a r3da470c  
    6767        virtual void visit( UntypedOffsetofExpr *offsetofExpr );
    6868        virtual void visit( OffsetofExpr *offsetofExpr );
     69        virtual void visit( OffsetPackExpr *offsetPackExpr );
    6970        virtual void visit( AttrExpr *attrExpr );
    7071        virtual void visit( LogicalExpr *logicalExpr );
  • src/Tuples/FlattenTuple.cc

    r630a82a r3da470c  
    4949        void FlattenTuple::CollectArgs::visit( UntypedOffsetofExpr *expr )  {  currentArgs.insert( currentArgs.end(), expr );  }
    5050        void FlattenTuple::CollectArgs::visit( OffsetofExpr        *expr )  {  currentArgs.insert( currentArgs.end(), expr );  }
     51        void FlattenTuple::CollectArgs::visit( OffsetPackExpr      *expr )  {  currentArgs.insert( currentArgs.end(), expr );  }
    5152        void FlattenTuple::CollectArgs::visit( AttrExpr            *expr )  {  currentArgs.insert( currentArgs.end(), expr );  }
    5253        void FlattenTuple::CollectArgs::visit( LogicalExpr         *expr )  {  currentArgs.insert( currentArgs.end(), expr );  }
  • src/Tuples/FlattenTuple.h

    r630a82a r3da470c  
    4545                        virtual void visit( UntypedOffsetofExpr * );
    4646                        virtual void visit( OffsetofExpr * );
     47                        virtual void visit( OffsetPackExpr * );
    4748                        virtual void visit( AttrExpr * );
    4849                        virtual void visit( LogicalExpr * );
Note: See TracChangeset for help on using the changeset viewer.