Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision e3e16bcf91a7300a6d1f71eaad04e2f3f498cfc2)
+++ src/GenPoly/Box.cc	(revision 982832e24b58f99cf8d892fbb03bfd2c5cd57b15)
@@ -27,4 +27,5 @@
 
 #include "CodeGen/OperatorTable.h"
+#include "Common/PassVisitor.h"          // for PassVisitor
 #include "Common/ScopedMap.h"            // for ScopedMap, ScopedMap<>::iter...
 #include "Common/SemanticError.h"        // for SemanticError
@@ -157,28 +158,24 @@
 		/// * Calculates polymorphic offsetof expressions from offset array
 		/// * Inserts dynamic calculation of polymorphic type layouts where needed
-		class PolyGenericCalculator final : public PolyMutator {
+		class PolyGenericCalculator final : public WithGuards, public WithVisitorRef<PolyGenericCalculator>, public WithStmtsToAdd, public WithDeclsToAdd, public WithTypeSubstitution {
 		public:
-			typedef PolyMutator Parent;
-			using Parent::mutate;
-
 			PolyGenericCalculator();
 
-			template< typename DeclClass >
-			DeclClass *handleDecl( DeclClass *decl, Type *type );
-			virtual DeclarationWithType *mutate( FunctionDecl *functionDecl ) override;
-			virtual ObjectDecl *mutate( ObjectDecl *objectDecl ) override;
-			virtual TypedefDecl *mutate( TypedefDecl *objectDecl ) override;
-			virtual TypeDecl *mutate( TypeDecl *objectDecl ) override;
-			virtual Statement *mutate( DeclStmt *declStmt ) override;
-			virtual Type *mutate( PointerType *pointerType ) override;
-			virtual Type *mutate( FunctionType *funcType ) override;
-			virtual Expression *mutate( MemberExpr *memberExpr ) override;
-			virtual Expression *mutate( SizeofExpr *sizeofExpr ) override;
-			virtual Expression *mutate( AlignofExpr *alignofExpr ) override;
-			virtual Expression *mutate( OffsetofExpr *offsetofExpr ) override;
-			virtual Expression *mutate( OffsetPackExpr *offsetPackExpr ) override;
-
-			virtual void doBeginScope() override;
-			virtual void doEndScope() override;
+			void premutate( ObjectDecl *objectDecl );
+			void premutate( FunctionDecl *functionDecl );
+			void premutate( TypedefDecl *objectDecl );
+			void premutate( TypeDecl *objectDecl );
+			Declaration * postmutate( TypeDecl *TraitDecl );
+			void premutate( PointerType *pointerType );
+			void premutate( FunctionType *funcType );
+			void premutate( DeclStmt *declStmt );
+			Expression *postmutate( MemberExpr *memberExpr );
+			Expression *postmutate( SizeofExpr *sizeofExpr );
+			Expression *postmutate( AlignofExpr *alignofExpr );
+			Expression *postmutate( OffsetofExpr *offsetofExpr );
+			Expression *postmutate( OffsetPackExpr *offsetPackExpr );
+
+			void beginScope();
+			void endScope();
 
 		private:
@@ -194,8 +191,11 @@
 			/// Exits the type-variable scope
 			void endTypeScope();
+			/// Enters a new scope for knowLayouts and knownOffsets and queues exit calls
+			void beginGenericScope();
 
 			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
 			UniqueName bufNamer;                           ///< Namer for VLA buffers
+			TyVarMap scopeTyVars;
 		};
 
@@ -250,5 +250,5 @@
 		Pass1 pass1;
 		Pass2 pass2;
-		PolyGenericCalculator polyCalculator;
+		PassVisitor<PolyGenericCalculator> polyCalculator;
 		Pass3 pass3;
 
@@ -256,5 +256,5 @@
 		mutateTranslationUnit/*All*/( translationUnit, pass1 );
 		mutateTranslationUnit/*All*/( translationUnit, pass2 );
-		mutateTranslationUnit/*All*/( translationUnit, polyCalculator );
+		mutateAll( translationUnit, polyCalculator );
 		mutateTranslationUnit/*All*/( translationUnit, pass3 );
 	}
@@ -555,5 +555,5 @@
 		TypeDecl *Pass1::mutate( TypeDecl *typeDecl ) {
 			addToTyVarMap( typeDecl, scopeTyVars );
-			return Mutator::mutate( typeDecl );
+			return dynamic_cast<TypeDecl*>( Mutator::mutate( typeDecl ) );
 		}
 
@@ -762,4 +762,10 @@
 				} else if ( arg->get_result()->get_lvalue() ) {
 					// argument expression may be CFA lvalue, but not C lvalue -- apply generalizedLvalue transformations.
+					// if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( arg ) ) {
+					// 	if ( dynamic_cast<ArrayType *>( varExpr->var->get_type() ) ){
+					// 		// temporary hack - don't box arrays, because &arr is not the same as &arr[0]
+					// 		return;
+					// 	}
+					// }
 					arg =  generalizedLvalue( new AddressExpr( arg ) );
 					if ( ! ResolvExpr::typesCompatible( param, arg->get_result(), SymTab::Indexer() ) ) {
@@ -1353,5 +1359,5 @@
 				return handleDecl( typeDecl );
 			} else {
-				return Parent::mutate( typeDecl );
+				return dynamic_cast<TypeDecl*>( Parent::mutate( typeDecl ) );
 			}
 		}
@@ -1466,62 +1472,60 @@
 
 		PolyGenericCalculator::PolyGenericCalculator()
-			: Parent(), knownLayouts(), knownOffsets(), bufNamer( "_buf" ) {}
+			: knownLayouts(), knownOffsets(), bufNamer( "_buf" ), scopeTyVars( TypeDecl::Data{} ) {}
 
 		void PolyGenericCalculator::beginTypeScope( Type *ty ) {
-			scopeTyVars.beginScope();
+			GuardScope( scopeTyVars );
 			makeTyVarMap( ty, scopeTyVars );
 		}
 
-		void PolyGenericCalculator::endTypeScope() {
-			scopeTyVars.endScope();
-		}
-
-		template< typename DeclClass >
-		DeclClass * PolyGenericCalculator::handleDecl( DeclClass *decl, Type *type ) {
-			beginTypeScope( type );
-			// knownLayouts.beginScope();
-			// knownOffsets.beginScope();
-
-			DeclClass *ret = static_cast< DeclClass *>( Parent::mutate( decl ) );
-
-			// knownOffsets.endScope();
-			// knownLayouts.endScope();
-			endTypeScope();
-			return ret;
-		}
-
-		ObjectDecl * PolyGenericCalculator::mutate( ObjectDecl *objectDecl ) {
-			return handleDecl( objectDecl, objectDecl->get_type() );
-		}
-
-		DeclarationWithType * PolyGenericCalculator::mutate( FunctionDecl *functionDecl ) {
-			knownLayouts.beginScope();
-			knownOffsets.beginScope();
-
-			DeclarationWithType * decl = handleDecl( functionDecl, functionDecl->get_functionType() );
-			knownOffsets.endScope();
-			knownLayouts.endScope();
-			return decl;
-		}
-
-		TypedefDecl * PolyGenericCalculator::mutate( TypedefDecl *typedefDecl ) {
-			return handleDecl( typedefDecl, typedefDecl->get_base() );
-		}
-
-		TypeDecl * PolyGenericCalculator::mutate( TypeDecl *typeDecl ) {
+		void PolyGenericCalculator::beginGenericScope() {
+			GuardScope( *this );
+		}
+
+		void PolyGenericCalculator::premutate( ObjectDecl *objectDecl ) {
+			beginTypeScope( objectDecl->get_type() );
+		}
+
+		void PolyGenericCalculator::premutate( FunctionDecl *functionDecl ) {
+			beginGenericScope();
+
+			beginTypeScope( functionDecl->get_functionType() );
+		}
+
+		void PolyGenericCalculator::premutate( TypedefDecl *typedefDecl ) {
+			beginTypeScope( typedefDecl->get_base() );
+		}
+
+		void PolyGenericCalculator::premutate( TypeDecl * typeDecl ) {
 			addToTyVarMap( typeDecl, scopeTyVars );
-			return Parent::mutate( typeDecl );
-		}
-
-		Type * PolyGenericCalculator::mutate( PointerType *pointerType ) {
+		}
+
+		Declaration * PolyGenericCalculator::postmutate( TypeDecl *typeDecl ) {
+			if ( Type * base = typeDecl->base ) {
+				// add size/align variables for opaque type declarations
+				TypeInstType inst( Type::Qualifiers(), typeDecl->name, typeDecl );
+				std::string typeName = mangleType( &inst );
+				Type *layoutType = new BasicType( Type::Qualifiers(), BasicType::LongUnsignedInt );
+
+				ObjectDecl * sizeDecl = ObjectDecl::newObject( sizeofName( typeName ), layoutType, new SingleInit( new SizeofExpr( base->clone() ) ) );
+				ObjectDecl * alignDecl = ObjectDecl::newObject( alignofName( typeName ), layoutType->clone(), new SingleInit( new AlignofExpr( base->clone() ) ) );
+
+				// ensure that the initializing sizeof/alignof exprs are properly mutated
+				sizeDecl->acceptMutator( *visitor );
+				alignDecl->acceptMutator( *visitor );
+
+				// can't use makeVar, because it inserts into stmtsToAdd and TypeDecls can occur at global scope
+				declsToAddAfter.push_back( alignDecl );
+				// replace with sizeDecl
+				return sizeDecl;
+			}
+			return typeDecl;
+		}
+
+		void PolyGenericCalculator::premutate( PointerType *pointerType ) {
 			beginTypeScope( pointerType );
-
-			Type *ret = Parent::mutate( pointerType );
-
-			endTypeScope();
-			return ret;
-		}
-
-		Type * PolyGenericCalculator::mutate( FunctionType *funcType ) {
+		}
+
+		void PolyGenericCalculator::premutate( FunctionType *funcType ) {
 			beginTypeScope( funcType );
 
@@ -1534,12 +1538,7 @@
 				}
 			}
-
-			Type *ret = Parent::mutate( funcType );
-
-			endTypeScope();
-			return ret;
-		}
-
-		Statement *PolyGenericCalculator::mutate( DeclStmt *declStmt ) {
+		}
+
+		void PolyGenericCalculator::premutate( DeclStmt *declStmt ) {
 			if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
 				if ( findGeneric( objectDecl->get_type() ) ) {
@@ -1550,5 +1549,5 @@
 						new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::Kind::Char), new NameExpr( sizeofName( mangleType(declType) ) ),
 						true, false, std::list<Attribute*>{ new Attribute( "aligned", std::list<Expression*>{ new ConstantExpr( Constant::from_int(8) ) } ) } ), 0 );
-					stmtsToAdd.push_back( new DeclStmt( noLabels, newBuf ) );
+					stmtsToAddBefore.push_back( new DeclStmt( noLabels, newBuf ) );
 
 					delete objectDecl->get_init();
@@ -1556,5 +1555,4 @@
 				}
 			}
-			return Parent::mutate( declStmt );
 		}
 
@@ -1583,10 +1581,5 @@
 		}
 
-		Expression *PolyGenericCalculator::mutate( MemberExpr *memberExpr ) {
-			// mutate, exiting early if no longer MemberExpr
-			Expression *expr = Parent::mutate( memberExpr );
-			memberExpr = dynamic_cast< MemberExpr* >( expr );
-			if ( ! memberExpr ) return expr;
-
+		Expression *PolyGenericCalculator::postmutate( MemberExpr *memberExpr ) {
 			// only mutate member expressions for polymorphic types
 			int tyDepth;
@@ -1635,5 +1628,5 @@
 		ObjectDecl *PolyGenericCalculator::makeVar( const std::string &name, Type *type, Initializer *init ) {
 			ObjectDecl *newObj = new ObjectDecl( name, Type::StorageClasses(), LinkageSpec::C, 0, type, init );
-			stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) );
+			stmtsToAddBefore.push_back( new DeclStmt( noLabels, newObj ) );
 			return newObj;
 		}
@@ -1714,5 +1707,5 @@
 					addOtypeParamsToLayoutCall( layoutCall, otypeParams );
 
-					stmtsToAdd.push_back( new ExprStmt( noLabels, layoutCall ) );
+					stmtsToAddBefore.push_back( new ExprStmt( noLabels, layoutCall ) );
 				}
 
@@ -1740,5 +1733,5 @@
 				addOtypeParamsToLayoutCall( layoutCall, otypeParams );
 
-				stmtsToAdd.push_back( new ExprStmt( noLabels, layoutCall ) );
+				stmtsToAddBefore.push_back( new ExprStmt( noLabels, layoutCall ) );
 
 				return true;
@@ -1748,5 +1741,5 @@
 		}
 
-		Expression *PolyGenericCalculator::mutate( SizeofExpr *sizeofExpr ) {
+		Expression *PolyGenericCalculator::postmutate( SizeofExpr *sizeofExpr ) {
 			Type *ty = sizeofExpr->get_isType() ? sizeofExpr->get_type() : sizeofExpr->get_expr()->get_result();
 			if ( findGeneric( ty ) ) {
@@ -1758,5 +1751,5 @@
 		}
 
-		Expression *PolyGenericCalculator::mutate( AlignofExpr *alignofExpr ) {
+		Expression *PolyGenericCalculator::postmutate( AlignofExpr *alignofExpr ) {
 			Type *ty = alignofExpr->get_isType() ? alignofExpr->get_type() : alignofExpr->get_expr()->get_result();
 			if ( findGeneric( ty ) ) {
@@ -1768,10 +1761,5 @@
 		}
 
-		Expression *PolyGenericCalculator::mutate( OffsetofExpr *offsetofExpr ) {
-			// mutate, exiting early if no longer OffsetofExpr
-			Expression *expr = Parent::mutate( offsetofExpr );
-			offsetofExpr = dynamic_cast< OffsetofExpr* >( expr );
-			if ( ! offsetofExpr ) return expr;
-
+		Expression *PolyGenericCalculator::postmutate( OffsetofExpr *offsetofExpr ) {
 			// only mutate expressions for polymorphic structs/unions
 			Type *ty = offsetofExpr->get_type();
@@ -1793,5 +1781,5 @@
 		}
 
-		Expression *PolyGenericCalculator::mutate( OffsetPackExpr *offsetPackExpr ) {
+		Expression *PolyGenericCalculator::postmutate( OffsetPackExpr *offsetPackExpr ) {
 			StructInstType *ty = offsetPackExpr->get_type();
 
@@ -1832,10 +1820,10 @@
 		}
 
-		void PolyGenericCalculator::doBeginScope() {
+		void PolyGenericCalculator::beginScope() {
 			knownLayouts.beginScope();
 			knownOffsets.beginScope();
 		}
 
-		void PolyGenericCalculator::doEndScope() {
+		void PolyGenericCalculator::endScope() {
 			knownLayouts.endScope();
 			knownOffsets.endScope();
@@ -1894,5 +1882,5 @@
 
 			addToTyVarMap( typeDecl, scopeTyVars );
-			return Mutator::mutate( typeDecl );
+			return dynamic_cast<TypeDecl*>( Mutator::mutate( typeDecl ) );
 		}
 
