Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 3cfe27f396428120b21372724bf1494f2e955648)
+++ src/GenPoly/Box.cc	(revision b3f9a0cb9de9429c2209a03c9f8cc182f8609da3)
@@ -30,4 +30,5 @@
 #include "FindFunction.h"
 #include "ScopedMap.h"
+#include "ScopedSet.h"
 #include "ScrubTyVars.h"
 
@@ -62,14 +63,15 @@
 		FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars );
 
-		/// Key for a unique concrete type; generic base type paired with type parameter list
-		struct ConcreteType {
-			ConcreteType() : base(NULL), params() {}
-
-			ConcreteType(AggregateDecl *_base, const std::list< Type* >& _params) : base(_base), params() { cloneAll(_params, params); }
-
-			ConcreteType(const ConcreteType& that) : base(that.base), params() { cloneAll(that.params, params); }
+		/// Abstracts type equality for a list of parameter types
+		struct TypeList {
+			TypeList() : params() {}
+			TypeList( const std::list< Type* > &_params ) : params() { cloneAll(_params, params); }
+			TypeList( std::list< Type* > &&_params ) : params( _params ) {}
+
+			TypeList( const TypeList &that ) : params() { cloneAll(that.params, params); }
+			TypeList( TypeList &&that ) : params( std::move( that.params ) ) {}
 
 			/// Extracts types from a list of TypeExpr*
-			ConcreteType(AggregateDecl *_base, const std::list< TypeExpr* >& _params) : base(_base), params() {
+			TypeList( const std::list< TypeExpr* >& _params ) : params() {
 				for ( std::list< TypeExpr* >::const_iterator param = _params.begin(); param != _params.end(); ++param ) {
 					params.push_back( (*param)->get_type()->clone() );
@@ -77,9 +79,8 @@
 			}
 
-			ConcreteType& operator= (const ConcreteType& that) {
+			TypeList& operator= ( const TypeList &that ) {
 				deleteAll( params );
+
 				params.clear();
-
-				base = that.base;
 				cloneAll( that.params, params );
 
@@ -87,11 +88,18 @@
 			}
 
-			~ConcreteType() { deleteAll( params ); }
-
-			bool operator== (const ConcreteType& that) const {
-				if ( base != that.base ) return false;
+			TypeList& operator= ( TypeList &&that ) {
+				deleteAll( params );
+
+				params = std::move( that.params );
+
+				return *this;
+			}
+
+			~TypeList() { deleteAll( params ); }
+
+			bool operator== ( const TypeList& that ) const {
+				if ( params.size() != that.params.size() ) return false;
 
 				SymTab::Indexer dummy;
-				if ( params.size() != that.params.size() ) return false;
 				for ( std::list< Type* >::const_iterator it = params.begin(), jt = that.params.begin(); it != params.end(); ++it, ++jt ) {
 					if ( ! ResolvExpr::typesCompatible( *it, *jt, dummy ) ) return false;
@@ -100,70 +108,44 @@
 			}
 
-			AggregateDecl *base;        ///< Base generic type
 			std::list< Type* > params;  ///< Instantiation parameters
 		};
 
-		/// Maps a concrete type to the some value, accounting for scope
-		template< typename Value >
+		/// Maps a key and a TypeList to the some value, accounting for scope
+		template< typename Key, typename Value >
 		class InstantiationMap {
-			/// Information about a specific instantiation of a generic type
-			struct Instantiation {
-				ConcreteType key;  ///< Instantiation parameters for this type
-				Value *value;      ///< Value for this instantiation
-
-				Instantiation() : key(), value(0) {}
-				Instantiation(const ConcreteType &_key, Value *_value) : key(_key), value(_value) {}
-			};
-			/// Map of generic types to instantiations of them
-			typedef std::map< AggregateDecl*, std::vector< Instantiation > > Scope;
-
-			std::vector< Scope > scopes;  ///< list of scopes, from outermost to innermost
+			/// Wraps value for a specific (Key, TypeList) combination
+			typedef std::pair< TypeList, Value* > Instantiation;
+			/// List of TypeLists paired with their appropriate values
+			typedef std::vector< Instantiation > ValueList;
+			/// Underlying map type; maps keys to a linear list of corresponding TypeLists and values
+			typedef ScopedMap< Key*, ValueList > InnerMap;
+
+			InnerMap instantiations;  ///< instantiations
 
 		public:
 			/// Starts a new scope
-			void beginScope() {
-				Scope scope;
-				scopes.push_back(scope);
-			}
+			void beginScope() { instantiations.beginScope(); }
 
 			/// Ends a scope
-			void endScope() {
-				scopes.pop_back();
-			}
-
-			/// Default constructor initializes with one scope
-			InstantiationMap() { beginScope(); }
-
-//		private:
-			/// Gets the value for the concrete instantiation of this type, assuming it has already been instantiated in the current scope.
-			/// Returns NULL on none such.
-			Value *lookup( AggregateDecl *generic, const std::list< TypeExpr* >& params ) {
-				ConcreteType key(generic, params);
-				// scan scopes from innermost out
-				for ( typename std::vector< Scope >::const_reverse_iterator scope = scopes.rbegin(); scope != scopes.rend(); ++scope ) {
-					// skip scope if no instantiations of this generic type
-					typename Scope::const_iterator insts = scope->find( generic );
-					if ( insts == scope->end() ) continue;
-					// look through instantiations for matches to concrete type
-					for ( typename std::vector< Instantiation >::const_iterator inst = insts->second.begin(); inst != insts->second.end(); ++inst ) {
-						if ( inst->key == key ) return inst->value;
+			void endScope() { instantiations.endScope(); }
+
+			/// Gets the value for the (key, typeList) pair, returns NULL on none such.
+			Value *lookup( Key *key, const std::list< TypeExpr* >& params ) const {
+ 				TypeList typeList( params );
+ 				
+				// scan scopes for matches to the key
+				for ( typename InnerMap::const_iterator insts = instantiations.find( key ); insts != instantiations.end(); insts = instantiations.findNext( insts, key ) ) {
+					for ( typename ValueList::const_reverse_iterator inst = insts->second.rbegin(); inst != insts->second.rend(); ++inst ) {
+						if ( inst->first == typeList ) return inst->second;
 					}
 				}
-				// no matching instantiation found
+				// no matching instantiations found
 				return 0;
 			}
-		public:
-//			StructDecl* lookup( StructInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (StructDecl*)lookup( inst->get_baseStruct(), typeSubs ); }
-//			UnionDecl* lookup( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (UnionDecl*)lookup( inst->get_baseUnion(), typeSubs ); }
-
-//		private:
-			/// Adds a value for a concrete type to the current scope
-			void insert( AggregateDecl *generic, const std::list< TypeExpr* > &params, Value *value ) {
-				ConcreteType key(generic, params);
-				scopes.back()[generic].push_back( Instantiation( key, value ) );
-			}
-//		public:
-//			void insert( StructInstType *inst, const std::list< TypeExpr* > &typeSubs, StructDecl *decl ) { insert( inst->get_baseStruct(), typeSubs, decl ); }
-//			void insert( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs, UnionDecl *decl ) { insert( inst->get_baseUnion(), typeSubs, decl ); }
+
+			/// Adds a value for a (key, typeList) pair to the current scope
+			void insert( Key *key, const std::list< TypeExpr* > &params, Value *value ) {
+				instantiations[ key ].push_back( Instantiation( TypeList( params ), value ) );
+			}
 		};
 
@@ -197,6 +179,4 @@
 			virtual void doEndScope();
 		  private:
-			/// Makes a new temporary array holding the offsets of the fields of `type`, and returns a new variable expression referencing it
-			Expression *makeOffsetArray( StructInstType *type );
 			/// Pass the extra type parameters from polymorphic generic arguments or return types into a function application
 			void passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes );
@@ -225,7 +205,8 @@
 			ObjectDecl *makeTemporary( Type *type );
 
-			std::map< std::string, DeclarationWithType *> assignOps;
-			ResolvExpr::TypeMap< DeclarationWithType > scopedAssignOps;
-			ScopedMap< std::string, DeclarationWithType* > adapters;
+			std::map< std::string, DeclarationWithType *> assignOps;     ///< Currently known type variable assignment operators
+			ResolvExpr::TypeMap< DeclarationWithType > scopedAssignOps;  ///< Currently known assignment operators
+			ScopedMap< std::string, DeclarationWithType* > adapters;     ///< Set of adapter functions in the current scope
+			
 			DeclarationWithType *retval;
 			bool useRetval;
@@ -233,5 +214,9 @@
 		};
 
-		/// Moves polymorphic returns in function types to pointer-type parameters, adds type size and assertion parameters to parameter lists as well
+		class OffsetPackExpr;  // forward declaration so that it can be mutated by Pass2
+
+		/// * Moves polymorphic returns in function types to pointer-type parameters
+		/// * adds type size and assertion parameters to parameter lists
+		/// * does dynamic calculation of type layouts
 		class Pass2 : public PolyMutator {
 		  public:
@@ -244,8 +229,64 @@
 			virtual Type *mutate( PointerType *pointerType );
 			virtual Type *mutate( FunctionType *funcType );
+			virtual Expression *mutate( SizeofExpr *sizeofExpr );
+			virtual Expression *mutate( AlignofExpr *alignofExpr );
+			virtual Expression *mutate( OffsetofExpr *offsetofExpr );
+			        Expression *mutate( OffsetPackExpr *offsetPackExpr );
+
+			virtual void doBeginScope();
+			virtual void doEndScope();
 		  private:
 			void addAdapters( FunctionType *functionType );
+			/// Makes a new variable in the current scope with the given name, type & optional initializer
+			ObjectDecl *makeVar( const std::string &name, Type *type, Initializer *init = 0 );
+			/// returns true if the type has a dynamic layout; such a layout will be stored in appropriately-named local variables when the function returns
+			bool findGeneric( Type *ty );
+			/// adds type parameters to the layout call; will generate the appropriate parameters if needed
+			void addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams );
 
 			std::map< UniqueId, std::string > adapterName;
+			ScopedSet< std::string > knownLayouts;          ///< Set of generic type layouts known in the current scope, indexed by sizeofName
+			ScopedSet< std::string > knownOffsets;          ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName
+		};
+
+		/// Special internal expression for offset arrays inserted by Pass1 and replaced by Pass2
+		class OffsetPackExpr : public Expression {
+		public:
+			OffsetPackExpr( StructInstType *type_, Expression *aname_ = 0 ) : Expression( aname_ ), type( type_ ) {
+					add_result( new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0, false, false ) );
+			}
+			
+			OffsetPackExpr( const OffsetPackExpr &other ) : Expression( other ), type( maybeClone( other.type ) ) {}
+			virtual ~OffsetPackExpr() { delete type; }
+
+			StructInstType *get_type() const { return type; }
+			void set_type( StructInstType *newValue ) { type = newValue; }
+
+			virtual OffsetPackExpr *clone() const { return new OffsetPackExpr( *this ); }
+			virtual void accept( Visitor &v ) { /* do nothing */ }
+			virtual Expression *acceptMutator( Mutator &m ) {
+				// only act if the mutator is a Pass2, which knows about this class
+				if ( Pass2 *m2 = dynamic_cast< Pass2* >( &m ) ) {
+					return m2->mutate( this );
+				} else {
+					return this;
+				}
+			}
+
+			virtual void print( std::ostream &os, int indent = 0 ) const {
+				os << std::string( indent, ' ' ) << "Offset pack expression on ";
+
+				if ( type ) {
+					type->print(os, indent + 2);
+				} else {
+					os << "<NULL>";
+				}
+
+				os << std::endl;
+				Expression::print( os, indent );
+			}
+			
+		private:
+			StructInstType *type;
 		};
 
@@ -253,5 +294,5 @@
 		class GenericInstantiator : public DeclMutator {
 			/// Map of (generic type, parameter list) pairs to concrete type instantiations
-			InstantiationMap< AggregateDecl > instantiations;
+			InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
 			/// Namer for concrete types
 			UniqueName typeNamer;
@@ -348,5 +389,4 @@
 		mutateTranslationUnit/*All*/( translationUnit, pass1 );
 		mutateTranslationUnit/*All*/( translationUnit, pass2 );
-//		instantiateGeneric( translationUnit );
 		instantiator.mutateDeclarationList( translationUnit );
 		mutateTranslationUnit/*All*/( translationUnit, memberFixer );
@@ -653,5 +693,5 @@
 
 		DeclarationWithType *Pass1::mutate( FunctionDecl *functionDecl ) {
-			// if this is a polymorphic assignment function, put it in the map for this scope
+			// if this is a assignment function, put it in the map for this scope
 			if ( Type *assignedType = isAssignment( functionDecl ) ) {
 				if ( ! dynamic_cast< TypeInstType* >( assignedType ) ) {
@@ -743,31 +783,4 @@
 		}
 
-		Expression *Pass1::makeOffsetArray( StructInstType *ty ) {
-			std::list< Declaration* > &baseMembers = ty->get_baseStruct()->get_members();
-
-			// make a new temporary array
-			Type *offsetType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
-			std::stringstream lenGen;
-			lenGen << baseMembers.size();
-			ConstantExpr *lenExpr = new ConstantExpr( Constant( offsetType->clone(), lenGen.str() ) );
-			ObjectDecl *arrayTemp = makeTemporary( new ArrayType( Type::Qualifiers(), offsetType, lenExpr, false, false ) );
-
-			// build initializer list for temporary
-			std::list< Initializer* > inits;
-			for ( std::list< Declaration* >::const_iterator member = baseMembers.begin(); member != baseMembers.end(); ++member ) {
-				DeclarationWithType *memberDecl;
-				if ( DeclarationWithType *origMember = dynamic_cast< DeclarationWithType* >( *member ) ) {
-					memberDecl = origMember->clone();
-				} else {
-					memberDecl = new ObjectDecl( (*member)->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, offsetType->clone(), 0 );
-				}
-				inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
-			}
-			arrayTemp->set_init( new ListInit( inits ) );
-
-			// return variable pointing to temporary
-			return new VariableExpr( arrayTemp );
-		}
-
 		void Pass1::passArgTypeVars( ApplicationExpr *appExpr, Type *parmType, Type *argBaseType, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars, std::set< std::string > &seenTypes ) {
 			Type *polyBase = hasPolyBase( parmType, exprTyVars );
@@ -782,6 +795,9 @@
 				if ( dynamic_cast< StructInstType* >( polyBase ) ) {
 					if ( StructInstType *argBaseStructType = dynamic_cast< StructInstType* >( argBaseType ) ) {
-						arg = appExpr->get_args().insert( arg, makeOffsetArray( argBaseStructType ) );
-						arg++;
+						// zero-length arrays are forbidden by C, so don't pass offset for empty struct
+						if ( ! argBaseStructType->get_baseStruct()->get_members().empty() ) {
+							arg = appExpr->get_args().insert( arg, new OffsetPackExpr( argBaseStructType ) );
+							arg++;
+						}
 					} else {
 						throw SemanticError( "Cannot pass non-struct type for generic struct" );
@@ -1587,5 +1603,4 @@
 			ObjectDecl newPtr( "", DeclarationNode::NoStorageClass, LinkageSpec::C, 0,
 			                   new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ) ), 0 );
-//   ObjectDecl *newFunPtr = new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) ), 0 );
 			for ( std::list< TypeDecl *>::const_iterator tyParm = funcType->get_forall().begin(); tyParm != funcType->get_forall().end(); ++tyParm ) {
 				ObjectDecl *sizeParm, *alignParm;
@@ -1631,12 +1646,16 @@
 					++last;
 
-					if ( dynamic_cast< StructInstType* >( polyBase ) ) {
-						offsetParm = newPtr.clone();
-						offsetParm->set_name( offsetofName( polyBase ) );
-						last = funcType->get_parameters().insert( last, offsetParm );
-						++last;
+					if ( StructInstType *polyBaseStruct = dynamic_cast< StructInstType* >( polyBase ) ) {
+						// NOTE zero-length arrays are illegal in C, so empty structs have no offset array
+						if ( ! polyBaseStruct->get_baseStruct()->get_members().empty() ) {
+							offsetParm = newPtr.clone();
+							offsetParm->set_name( offsetofName( polyBase ) );
+							last = funcType->get_parameters().insert( last, offsetParm );
+							++last;
+						}
 					}
 
 					seenTypes.insert( sizeName );
+					knownLayouts.insert( sizeName );  // make sure that any type information passed into the function is accounted for
 				}
 			}
@@ -1650,4 +1669,187 @@
 			scopeTyVars = oldtyVars;
 			return funcType;
+		}
+
+		ObjectDecl *Pass2::makeVar( const std::string &name, Type *type, Initializer *init ) {
+			ObjectDecl *newObj = new ObjectDecl( name, DeclarationNode::NoStorageClass, LinkageSpec::C, 0, type, init );
+			stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) );
+			return newObj;
+		}
+
+		void Pass2::addOtypeParamsToLayoutCall( UntypedExpr *layoutCall, const std::list< Type* > &otypeParams ) {
+			for ( std::list< Type* >::const_iterator param = otypeParams.begin(); param != otypeParams.end(); ++param ) {
+				if ( findGeneric( *param ) ) {
+					// push size/align vars for a generic parameter back
+					layoutCall->get_args().push_back( new NameExpr( sizeofName( *param ) ) );
+					layoutCall->get_args().push_back( new NameExpr( alignofName( *param ) ) );
+				} else {
+					layoutCall->get_args().push_back( new SizeofExpr( *param ) );
+					layoutCall->get_args().push_back( new AlignofExpr( *param ) );
+				}
+			}
+		}
+
+		/// returns true if any of the otype parameters have a dynamic layout and puts all otype parameters in the output list
+		bool findGenericParams( std::list< TypeDecl* > &baseParams, std::list< Expression* > &typeParams, std::list< Type* > &out ) {
+			bool hasDynamicLayout = false;
+
+			std::list< TypeDecl* >::const_iterator baseParam = baseParams.begin();
+			std::list< Expression* >::const_iterator typeParam = typeParams.begin();
+			for ( ; baseParam != baseParams.end() && typeParam != typeParams.end(); ++baseParam, ++typeParam ) {
+				// skip non-otype parameters
+				if ( (*baseParam)->get_kind() != TypeDecl::Any ) continue;
+				TypeExpr *typeExpr = dynamic_cast< TypeExpr* >( *typeParam );
+				assert( typeExpr && "all otype parameters should be type expressions" );
+
+				Type *type = typeExpr->get_type();
+				out.push_back( type );
+				if ( isPolyType( type ) ) hasDynamicLayout = true;
+			}
+			assert( baseParam == baseParams.end() && typeParam == typeParams.end() );
+
+			return hasDynamicLayout;
+		}
+		
+		bool Pass2::findGeneric( Type *ty ) {
+			if ( dynamic_cast< TypeInstType* >( ty ) ) {
+				// NOTE this assumes that all type variables will be properly bound, and thus have their layouts in scope
+				return true;
+			} else if ( StructInstType *structTy = dynamic_cast< StructInstType* >( ty ) ) {
+				// check if this type already has a layout generated for it
+				std::string sizeName = sizeofName( ty );
+				if ( knownLayouts.find( sizeName ) != knownLayouts.end() ) return true;
+				
+				// check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
+				std::list< Type* > otypeParams;
+				if ( ! findGenericParams( *structTy->get_baseParameters(), structTy->get_parameters(), otypeParams ) ) return false;
+
+				// insert local variables for layout and generate call to layout function
+				knownLayouts.insert( sizeName );  // done early so as not to interfere with the later addition of parameters to the layout call
+				Type *layoutType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
+
+				int n_members = structTy->get_baseStruct()->get_members().size();
+				if ( n_members == 0 ) {
+					// all empty structs have the same layout - size 1, align 1
+					makeVar( sizeName, layoutType, new SingleInit( new ConstantExpr( Constant::from( (unsigned long)1 ) ) ) );
+					makeVar( alignofName( ty ), layoutType->clone(), new SingleInit( new ConstantExpr( Constant::from( (unsigned long)1 ) ) ) );
+					// NOTE zero-length arrays are forbidden in C, so empty structs have no offsetof array
+				} else {
+					ObjectDecl *sizeVar = makeVar( sizeName, layoutType );
+					ObjectDecl *alignVar = makeVar( alignofName( ty ), layoutType->clone() );
+					ObjectDecl *offsetVar = makeVar( offsetofName( ty ), new ArrayType( Type::Qualifiers(), layoutType->clone(), new ConstantExpr( Constant::from( n_members ) ), false, false ) );
+
+					// generate call to layout function
+					UntypedExpr *layoutCall = new UntypedExpr( new NameExpr( "__layoutof_" + structTy->get_baseStruct()->get_name() ) );
+					layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( sizeVar ) ) );
+					layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( alignVar ) ) );
+					layoutCall->get_args().push_back( new VariableExpr( offsetVar ) );
+					addOtypeParamsToLayoutCall( layoutCall, otypeParams );
+
+					stmtsToAdd.push_back( new ExprStmt( noLabels, layoutCall ) );
+				}
+				
+				return true;
+			} else if ( UnionInstType *unionTy = dynamic_cast< UnionInstType* >( ty ) ) {
+				// check if this type already has a layout generated for it
+				std::string sizeName = sizeofName( ty );
+				if ( knownLayouts.find( sizeName ) != knownLayouts.end() ) return true;
+				
+				// check if any of the type parameters have dynamic layout; if none do, this type is (or will be) monomorphized
+				std::list< Type* > otypeParams;
+				if ( ! findGenericParams( *unionTy->get_baseParameters(), unionTy->get_parameters(), otypeParams ) ) return false;
+
+				// insert local variables for layout and generate call to layout function
+				knownLayouts.insert( sizeName );  // done early so as not to interfere with the later addition of parameters to the layout call
+				Type *layoutType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
+
+				ObjectDecl *sizeVar = makeVar( sizeName, layoutType );
+				ObjectDecl *alignVar = makeVar( alignofName( ty ), layoutType->clone() );
+				
+				// generate call to layout function
+				UntypedExpr *layoutCall = new UntypedExpr( new NameExpr( "__layoutof_" + unionTy->get_baseUnion()->get_name() ) );
+				layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( sizeVar ) ) );
+				layoutCall->get_args().push_back( new AddressExpr( new VariableExpr( alignVar ) ) );
+				addOtypeParamsToLayoutCall( layoutCall, otypeParams );
+
+				stmtsToAdd.push_back( new ExprStmt( noLabels, layoutCall ) );
+
+				return true;
+			}
+			
+			return false;
+		}
+		
+		Expression *Pass2::mutate( SizeofExpr *sizeofExpr ) {
+			Type *ty = sizeofExpr->get_type();
+			if ( findGeneric( ty ) ) {
+				Expression *ret = new NameExpr( sizeofName( ty ) );
+				delete sizeofExpr;
+				return ret;
+			}
+			return sizeofExpr;
+		}
+
+		Expression *Pass2::mutate( AlignofExpr *alignofExpr ) {
+			Type *ty = alignofExpr->get_type();
+			if ( findGeneric( ty ) ) {
+				Expression *ret = new NameExpr( alignofName( ty ) );
+				delete alignofExpr;
+				return ret;
+			}
+			return alignofExpr;
+		}
+
+		Expression *Pass2::mutate( OffsetofExpr *offsetofExpr ) {
+			findGeneric( offsetofExpr->get_type() );
+			return offsetofExpr;
+		}
+
+		Expression *Pass2::mutate( OffsetPackExpr *offsetPackExpr ) {
+			StructInstType *ty = offsetPackExpr->get_type();
+
+			Expression *ret = 0;
+			if ( findGeneric( ty ) ) {
+				// pull offset back from generated type information
+				ret = new NameExpr( offsetofName( ty ) );
+			} else {
+				std::string offsetName = offsetofName( ty );
+				if ( knownOffsets.find( offsetName ) != knownOffsets.end() ) {
+					// use the already-generated offsets for this type
+					ret = new NameExpr( offsetName );
+				} else {
+					std::list< Declaration* > &baseMembers = ty->get_baseStruct()->get_members();
+					Type *offsetType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
+
+					// build initializer list for offset array
+					std::list< Initializer* > inits;
+					for ( std::list< Declaration* >::const_iterator member = baseMembers.begin(); member != baseMembers.end(); ++member ) {
+						DeclarationWithType *memberDecl;
+						if ( DeclarationWithType *origMember = dynamic_cast< DeclarationWithType* >( *member ) ) {
+							memberDecl = origMember->clone();
+						} else {
+							memberDecl = new ObjectDecl( (*member)->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, offsetType->clone(), 0 );
+						}
+						inits.push_back( new SingleInit( new OffsetofExpr( ty->clone(), memberDecl ) ) );
+					}
+
+					// build the offset array and replace the pack with a reference to it
+					ObjectDecl *offsetArray = makeVar( offsetName, new ArrayType( Type::Qualifiers(), offsetType, new ConstantExpr( Constant::from( baseMembers.size() ) ), false, false ),
+							new ListInit( inits ) );
+					ret = new VariableExpr( offsetArray );
+				}
+			}
+
+			delete offsetPackExpr;
+			return ret;
+		}
+
+		void Pass2::doBeginScope() {
+			knownLayouts.beginScope();
+			knownOffsets.beginScope();
+		}
+		
+		void Pass2::doEndScope() {
+			knownLayouts.endScope();
+			knownOffsets.beginScope();
 		}
 
Index: src/GenPoly/ScopedMap.h
===================================================================
--- src/GenPoly/ScopedMap.h	(revision 3cfe27f396428120b21372724bf1494f2e955648)
+++ src/GenPoly/ScopedMap.h	(revision b3f9a0cb9de9429c2209a03c9f8cc182f8609da3)
@@ -17,4 +17,5 @@
 #define _SCOPEDMAP_H
 
+#include <cassert>
 #include <iterator>
 #include <map>
@@ -164,4 +165,5 @@
 		void endScope() {
 			scopes.pop_back();
+			assert( ! scopes.empty() );
 		}
 
@@ -188,5 +190,7 @@
 			return end();
 		}
-		const_iterator find( const Key &key ) const { return const_iterator( find( key ) ); }
+		const_iterator find( const Key &key ) const {
+				return const_iterator( const_cast< ScopedMap< Key, Value >* >(this)->find( key ) );
+		}
 		
 		/// Finds the given key in the outermost scope inside the given scope where it occurs
@@ -200,5 +204,7 @@
 			return end();
 		}
-		const_iterator findNext( const_iterator &it, const Key &key ) const { return const_iterator( findNext( it, key ) ); }
+		const_iterator findNext( const_iterator &it, const Key &key ) const {
+				return const_iterator( const_cast< ScopedMap< Key, Value >* >(this)->findNext( it, key ) );
+		}
 
 		/// Inserts the given key-value pair into the outermost scope
@@ -208,5 +214,10 @@
 		}
 		std::pair< iterator, bool > insert( const Key &key, const Value &value ) { return insert( std::make_pair( key, value ) ); }
-		
+
+		Value& operator[] ( const Key &key ) {
+			iterator slot = find( key );
+			if ( slot != end() ) return slot->second;
+			return insert( key, Value() ).first->second;
+		}
 	};
 } // namespace GenPoly
