Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision bfebb6c512a570fafd6d6e1a84b2304ca7bd5365)
+++ src/GenPoly/Box.cc	(revision 05d472781f65644ac06288649bee186de41bf983)
@@ -22,4 +22,5 @@
 
 #include "Box.h"
+#include "InstantiateGeneric.h"
 #include "PolyMutator.h"
 #include "FindFunction.h"
@@ -70,4 +71,7 @@
 			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 );
+			/// passes extra type parameters into a polymorphic function application
 			void passTypeVars( ApplicationExpr *appExpr, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
 			/// wraps a function application with a new temporary for the out-parameter return value
@@ -88,5 +92,7 @@
 			void passAdapters( ApplicationExpr *appExpr, FunctionType *functionType, const TyVarMap &exprTyVars );
 			FunctionDecl *makeAdapter( FunctionType *adaptee, FunctionType *realType, const std::string &mangleName, const TyVarMap &tyVars );
+			/// Replaces intrinsic operator functions with their arithmetic desugaring
 			Expression *handleIntrinsics( ApplicationExpr *appExpr );
+			/// Inserts a new temporary variable into the current scope with an auto-generated name
 			ObjectDecl *makeTemporary( Type *type );
 
@@ -117,6 +123,6 @@
 		};
 
-		/// Replaces initialization of polymorphic values with alloca, declaration of dtype/ftype with appropriate void expression, and sizeof expressions of polymorphic types with the proper variable
-		class Pass3 : public PolyMutator {
+		/// Replaces member expressions for polymorphic types with calculated add-field-offset-and-dereference
+		class MemberExprFixer : public PolyMutator {
 		  public:
 			template< typename DeclClass >
@@ -129,4 +135,18 @@
 			virtual Type *mutate( PointerType *pointerType );
 			virtual Type *mutate( FunctionType *funcType );
+			virtual Expression *mutate( MemberExpr *memberExpr );
+		};
+		
+		/// Replaces initialization of polymorphic values with alloca, declaration of dtype/ftype with appropriate void expression, and sizeof expressions of polymorphic types with the proper variable
+		class Pass3 : public PolyMutator {
+		  public:
+			template< typename DeclClass >
+			DeclClass *handleDecl( DeclClass *decl, Type *type );
+			virtual DeclarationWithType *mutate( FunctionDecl *functionDecl );
+			virtual ObjectDecl *mutate( ObjectDecl *objectDecl );
+			virtual TypedefDecl *mutate( TypedefDecl *objectDecl );
+			virtual TypeDecl *mutate( TypeDecl *objectDecl );
+			virtual Type *mutate( PointerType *pointerType );
+			virtual Type *mutate( FunctionType *funcType );
 		  private:
 		};
@@ -143,11 +163,40 @@
 	}
 
+	/// version of mutateAll with special handling for translation unit so you can check the end of the prelude when debugging
+	template< typename MutatorType >
+	inline void mutateTranslationUnit( std::list< Declaration* > &translationUnit, MutatorType &mutator ) {
+		bool seenIntrinsic = false;
+		SemanticError errors;
+		for ( typename std::list< Declaration* >::iterator i = translationUnit.begin(); i != translationUnit.end(); ++i ) {
+			try {
+				if ( *i ) {
+					if ( (*i)->get_linkage() == LinkageSpec::Intrinsic ) {
+						seenIntrinsic = true;
+					} else if ( seenIntrinsic ) {
+						seenIntrinsic = false; // break on this line when debugging for end of prelude
+					}
+					
+					*i = dynamic_cast< Declaration* >( (*i)->acceptMutator( mutator ) );
+					assert( *i );
+				} // if
+			} catch( SemanticError &e ) {
+				errors.append( e );
+			} // try
+		} // for
+		if ( ! errors.isEmpty() ) {
+			throw errors;
+		} // if
+	}
+
 	void box( std::list< Declaration *>& translationUnit ) {
 		Pass1 pass1;
 		Pass2 pass2;
+		MemberExprFixer memberFixer;
 		Pass3 pass3;
-		mutateAll( translationUnit, pass1 );
-		mutateAll( translationUnit, pass2 );
-		mutateAll( translationUnit, pass3 );
+		mutateTranslationUnit/*All*/( translationUnit, pass1 );
+		mutateTranslationUnit/*All*/( translationUnit, pass2 );
+		instantiateGeneric( translationUnit );
+		mutateTranslationUnit/*All*/( translationUnit, memberFixer );
+		mutateTranslationUnit/*All*/( translationUnit, pass3 );
 	}
 
@@ -269,4 +318,5 @@
 					findFunction( (*arg)->get_type(), functions, scopeTyVars, needsAdapter );
 				} // for
+				
 				AdapterMap & adapters = Pass1::adapters.top();
 				for ( std::list< FunctionType *>::iterator funType = functions.begin(); funType != functions.end(); ++funType ) {
@@ -319,4 +369,27 @@
 		}
 
+		Expression *Pass1::makeOffsetArray( StructInstType *ty ) {
+			// make a new temporary array
+			Type *offsetType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
+			ObjectDecl *arrayTemp = makeTemporary( new PointerType( Type::Qualifiers(), offsetType ) );
+
+			// build initializer list for temporary
+			std::list< Initializer* > inits;
+			StructDecl *tyBase = ty->get_baseStruct();
+			for ( std::list< Declaration* >::const_iterator member = tyBase->get_members().begin(); member != tyBase->get_members().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::passTypeVars( ApplicationExpr *appExpr, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars ) {
 			// pass size/align for type variables
@@ -338,5 +411,4 @@
 
 			// add size/align for generic types to parameter list
-			//assert( ! appExpr->get_function()->get_results().empty() );
 			if ( appExpr->get_function()->get_results().empty() ) return;
 			FunctionType *funcType = getFunctionType( appExpr->get_function()->get_results().front() );
@@ -358,4 +430,12 @@
 					arg = appExpr->get_args().insert( arg, new AlignofExpr( argType->clone() ) );
 					arg++;
+					if ( dynamic_cast< StructInstType* >( parmType ) ) {
+						if ( StructInstType *argStructType = dynamic_cast< StructInstType* >( argType ) ) {
+							arg = appExpr->get_args().insert( arg, makeOffsetArray( argStructType ) );
+							arg++;
+						} else {
+							throw SemanticError( "Cannot pass non-struct type for generic struct" );
+						}
+					}
 
 					seenTypes.insert( sizeName );
@@ -929,6 +1009,9 @@
 						throw SemanticError( "Attempt to return dtype or ftype generic object in ", returnStmt->get_expr() );
 					}
-					assignDecl = new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0,
-												 new PointerType( Type::Qualifiers(), assignIter->second->get_type()->clone() ), 0 );
+					DeclarationWithType *functionDecl = assignIter->second;
+					// line below cloned from FixFunction.cc
+					assignDecl = new ObjectDecl( functionDecl->get_name(), functionDecl->get_storageClass(), functionDecl->get_linkage(), 0,
+					                             new PointerType( Type::Qualifiers(), functionDecl->get_type()->clone() ), 0 );
+					assignDecl->set_mangleName( functionDecl->get_mangleName() );
 				}
 				assert( assignDecl );
@@ -1060,4 +1143,6 @@
 			std::list< DeclarationWithType *> inferredParams;
 			ObjectDecl newObj( "", DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), 0 );
+			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 ) {
@@ -1093,5 +1178,5 @@
 					if ( seenTypes.count( sizeName ) ) continue;
 
-					ObjectDecl *sizeParm, *alignParm;
+					ObjectDecl *sizeParm, *alignParm, *offsetParm;
 					sizeParm = newObj.clone();
 					sizeParm->set_name( sizeName );
@@ -1103,4 +1188,11 @@
 					last = funcType->get_parameters().insert( last, alignParm );
 					++last;
+
+					if ( dynamic_cast< StructInstType* >( parmType ) ) {
+						offsetParm = newPtr.clone();
+						offsetParm->set_name( offsetofName( parmType ) );
+						last = funcType->get_parameters().insert( last, offsetParm );
+						++last;
+					}
 
 					seenTypes.insert( sizeName );
@@ -1116,4 +1208,129 @@
 			scopeTyVars = oldtyVars;
 			return funcType;
+		}
+
+////////////////////////////////////////// MemberExprFixer ////////////////////////////////////////////////////
+
+		template< typename DeclClass >
+		DeclClass * MemberExprFixer::handleDecl( DeclClass *decl, Type *type ) {
+			TyVarMap oldtyVars = scopeTyVars;
+			makeTyVarMap( type, scopeTyVars );
+
+			DeclClass *ret = static_cast< DeclClass *>( Mutator::mutate( decl ) );
+
+			scopeTyVars = oldtyVars;
+			return ret;
+		}
+
+		ObjectDecl * MemberExprFixer::mutate( ObjectDecl *objectDecl ) {
+			return handleDecl( objectDecl, objectDecl->get_type() );
+		}
+
+		DeclarationWithType * MemberExprFixer::mutate( FunctionDecl *functionDecl ) {
+			return handleDecl( functionDecl, functionDecl->get_functionType() );
+		}
+
+		TypedefDecl * MemberExprFixer::mutate( TypedefDecl *typedefDecl ) {
+			return handleDecl( typedefDecl, typedefDecl->get_base() );
+		}
+
+		TypeDecl * MemberExprFixer::mutate( TypeDecl *typeDecl ) {
+			scopeTyVars[ typeDecl->get_name() ] = typeDecl->get_kind();
+			return Mutator::mutate( typeDecl );
+		}
+
+		Type * MemberExprFixer::mutate( PointerType *pointerType ) {
+			TyVarMap oldtyVars = scopeTyVars;
+			makeTyVarMap( pointerType, scopeTyVars );
+
+			Type *ret = Mutator::mutate( pointerType );
+
+			scopeTyVars = oldtyVars;
+			return ret;
+		}
+
+		Type * MemberExprFixer::mutate( FunctionType *functionType ) {
+			TyVarMap oldtyVars = scopeTyVars;
+			makeTyVarMap( functionType, scopeTyVars );
+
+			Type *ret = Mutator::mutate( functionType );
+
+			scopeTyVars = oldtyVars;
+			return ret;
+		}
+
+		Statement *MemberExprFixer::mutate( DeclStmt *declStmt ) {
+			if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
+				if ( isPolyType( objectDecl->get_type(), scopeTyVars ) ) {
+					// change initialization of a polymorphic value object
+					// to allocate storage with alloca
+					Type *declType = objectDecl->get_type();
+					UntypedExpr *alloc = new UntypedExpr( new NameExpr( "__builtin_alloca" ) );
+					alloc->get_args().push_back( new NameExpr( sizeofName( declType ) ) );
+
+					delete objectDecl->get_init();
+
+					std::list<Expression*> designators;
+					objectDecl->set_init( new SingleInit( alloc, designators ) );
+				}
+			}
+			return Mutator::mutate( declStmt );
+		}
+
+		Expression *MemberExprFixer::mutate( MemberExpr *memberExpr ) {
+			// mutate, exiting early if no longer MemberExpr
+			Expression *expr = Mutator::mutate( memberExpr );
+			memberExpr = dynamic_cast< MemberExpr* >( expr );
+			if ( ! memberExpr ) return expr;
+
+			// get declaration for base struct, exiting early if not found
+			VariableExpr *varExpr = getBaseVar( memberExpr->get_aggregate() );
+			if ( ! varExpr ) return memberExpr;
+			ObjectDecl *objectDecl = dynamic_cast< ObjectDecl* >( varExpr->get_var() );
+			if ( ! objectDecl ) return memberExpr;
+
+			// only mutate member expressions for polymorphic types
+			Type *objectType = hasPolyBase( objectDecl->get_type(), scopeTyVars );
+			if ( ! objectType ) return memberExpr;
+
+			// get base aggregate for type so members can be looked up
+			AggregateDecl *memberBase = 0;
+			if ( StructInstType *structType = dynamic_cast< StructInstType* >( objectType ) ) {
+				memberBase = structType->get_baseStruct();
+			} else if ( UnionInstType *unionType = dynamic_cast< UnionInstType* >( objectType ) ) {
+				memberBase = unionType->get_baseUnion();
+			} else return memberExpr;
+
+			// look up numeric index of member in base aggregate
+			DeclarationWithType *memberDecl = memberExpr->get_member();
+			std::list< Declaration* > &baseDecls = memberBase->get_members();
+			std::list< Declaration* >::const_iterator decl = baseDecls.begin();
+			unsigned long i = 0;
+			for( ; decl != baseDecls.end(); ++decl, ++i ) {
+				if ( memberDecl->get_name() != (*decl)->get_name() ) continue;
+
+				if ( DeclarationWithType *declWithType = dynamic_cast< DeclarationWithType* >( *decl ) ) {
+					if ( memberDecl->get_mangleName() == declWithType->get_mangleName() ) break;
+					else continue;
+				} else break;
+			}
+			if ( decl == baseDecls.end() ) return memberExpr;
+
+			// replace member expression with dereference of pointer offset
+			std::stringstream offset_namer;
+			offset_namer << i;
+			ConstantExpr *fieldIndex = new ConstantExpr( Constant( new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt ), offset_namer.str() ) );
+			UntypedExpr *fieldOffset = new UntypedExpr( new NameExpr( "?[?]" ) );
+			fieldOffset->get_args().push_back( new NameExpr( offsetofName( objectType ) ) );
+			fieldOffset->get_args().push_back( fieldIndex );
+			UntypedExpr *fieldLoc = new UntypedExpr( new NameExpr( "?+?" ) );
+			fieldLoc->get_args().push_back( memberExpr->get_aggregate() );
+			fieldLoc->get_args().push_back( fieldOffset );
+			UntypedExpr *ret = new UntypedExpr( new NameExpr( "*?" ) );
+			ret->get_args().push_back( fieldLoc );
+
+			memberExpr->set_aggregate( 0 );
+			delete memberExpr;
+			return ret;
 		}
 
@@ -1176,22 +1393,4 @@
 			return ret;
 		}
-
-		Statement *Pass3::mutate( DeclStmt *declStmt ) {
-			if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
-				if ( isPolyType( objectDecl->get_type(), scopeTyVars ) ) {
-					// change initialization of a polymorphic value object
-					// to allocate storage with alloca
-					Type *declType = objectDecl->get_type();
-					UntypedExpr *alloc = new UntypedExpr( new NameExpr( "__builtin_alloca" ) );
-					alloc->get_args().push_back( new NameExpr( sizeofName( declType ) ) );
-
-					delete objectDecl->get_init();
-
-					std::list<Expression*> designators;
-					objectDecl->set_init( new SingleInit( alloc, designators ) );
-				}
-			}
-			return Mutator::mutate( declStmt );
-		}
 	} // anonymous namespace
 } // namespace GenPoly
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision bfebb6c512a570fafd6d6e1a84b2304ca7bd5365)
+++ src/GenPoly/GenPoly.cc	(revision 05d472781f65644ac06288649bee186de41bf983)
@@ -127,4 +127,32 @@
 	}
 
+	Type *hasPolyBase( Type *type, const TypeSubstitution *env ) {
+		if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
+			return hasPolyBase( ptr->get_base(), env );
+		} else if ( env ) {
+			if ( TypeInstType *typeInst = dynamic_cast< TypeInstType *>( type ) ) {
+				if ( Type *newType = env->lookup( typeInst->get_name() ) ) {
+					return hasPolyBase( newType, env );
+				} // if
+			} // if
+		}
+
+		return isPolyType( type, env );
+	}
+	
+	Type *hasPolyBase( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env ) {
+		if ( PointerType *ptr = dynamic_cast< PointerType *>( type ) ) {
+			return hasPolyBase( ptr->get_base(), tyVars, env );
+		} else if ( env ) {
+			if ( TypeInstType *typeInst = dynamic_cast< TypeInstType *>( type ) ) {
+				if ( Type *newType = env->lookup( typeInst->get_name() ) ) {
+					return hasPolyBase( newType, tyVars, env );
+				} // if
+			} // if
+		}
+
+		return isPolyType( type, tyVars, env );
+	}
+
 	FunctionType * getFunctionType( Type *ty ) {
 		PointerType *ptrType;
@@ -136,4 +164,16 @@
 	}
 
+	VariableExpr *getBaseVar( Expression *expr ) {
+		if ( VariableExpr *varExpr = dynamic_cast< VariableExpr* >( expr ) ) {
+			// found the variable directly
+			return varExpr;
+		} else if ( UntypedExpr *untypedExpr = dynamic_cast< UntypedExpr* >( expr ) ) {
+			// look for compiler-inserted dereference operator
+			NameExpr *fn = dynamic_cast< NameExpr* >( untypedExpr->get_function() );
+			if ( ! fn || fn->get_name() != std::string("*?") ) return 0;
+			return getBaseVar( *untypedExpr->begin_args() );
+		} else return 0;
+	}
+
 	void makeTyVarMap( Type *type, TyVarMap &tyVarMap ) {
 		for ( std::list< TypeDecl* >::const_iterator tyVar = type->get_forall().begin(); tyVar != type->get_forall().end(); ++tyVar ) {
@@ -160,4 +200,9 @@
 		return std::string( "_alignof_" ) + SymTab::Mangler::mangleType( ty );
 	}
+
+	std::string offsetofName( Type* ty ) {
+		return std::string( "_offsetof_" ) + SymTab::Mangler::mangleType( ty );
+	}
+
 } // namespace GenPoly
 
Index: src/GenPoly/GenPoly.h
===================================================================
--- src/GenPoly/GenPoly.h	(revision bfebb6c512a570fafd6d6e1a84b2304ca7bd5365)
+++ src/GenPoly/GenPoly.h	(revision 05d472781f65644ac06288649bee186de41bf983)
@@ -47,6 +47,17 @@
 	Type *isPolyPtr( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
 
+	/// returns polymorphic base type if the base type (after dereferencing any number of pointers) is a polymorphic type, NULL otherwise;
+	/// will look up substitution in env if provided
+	Type *hasPolyBase( Type *type, const TypeSubstitution *env = 0 );
+
+	/// returns polymorphic base type if the base type (after dereferencing any number of pointers) is a polymorphic type in tyVars, NULL otherwise;
+	/// will look up substitution in env if provided
+	Type *hasPolyBase( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
+
 	/// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise
-	FunctionType * getFunctionType( Type *ty );
+	FunctionType *getFunctionType( Type *ty );
+
+	/// Returns the base variable (possibly repeatedly dereferenced) for an expression, NULL if none found
+	VariableExpr *getBaseVar( Expression *expr );
 
 	/// Adds the declarations in the forall list of type (and its pointed-to type if it's a pointer type) to `tyVarMap`
@@ -61,4 +72,7 @@
 	/// Gets the name of the alignof parameter for the type
 	std::string alignofName( Type *ty );
+
+	/// Gets the name of the offsetof parameter for the type
+	std::string offsetofName( Type *ty );
 } // namespace GenPoly
 
Index: src/SynTree/Initializer.h
===================================================================
--- src/SynTree/Initializer.h	(revision bfebb6c512a570fafd6d6e1a84b2304ca7bd5365)
+++ src/SynTree/Initializer.h	(revision 05d472781f65644ac06288649bee186de41bf983)
@@ -55,5 +55,5 @@
 class SingleInit : public Initializer {
   public:
-	SingleInit( Expression *value, std::list< Expression *> &designators );
+	SingleInit( Expression *value, std::list< Expression *> &designators = *(new std::list<Expression *>()) );
 	SingleInit( const SingleInit &other );
 	virtual ~SingleInit();
Index: src/main.cc
===================================================================
--- src/main.cc	(revision bfebb6c512a570fafd6d6e1a84b2304ca7bd5365)
+++ src/main.cc	(revision 05d472781f65644ac06288649bee186de41bf983)
@@ -24,5 +24,4 @@
 #include "SynTree/Declaration.h"
 #include "SynTree/Visitor.h"
-#include "GenPoly/InstantiateGeneric.h"
 #include "GenPoly/Lvalue.h"
 #include "GenPoly/Specialize.h"
@@ -273,7 +272,5 @@
 		OPTPRINT( "box" )
 		GenPoly::box( translationUnit );
-		OPTPRINT( "instantiateGeneric" )
-		GenPoly::instantiateGeneric( translationUnit );
-
+		
 		// print tree right before code generation
 		if ( codegenp ) {
