Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision 4a8f15041541ed05d71e64f45bf5cca3616efdcb)
+++ src/InitTweak/GenInit.cc	(revision 075b8fd5fa47384b08835c49a00471200d18c4e1)
@@ -122,6 +122,32 @@
 	};
 
+	struct HoistArrayDimension_NoResolve final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
+		/// hoist dimension from array types in object declaration so that it uses a single
+		/// const variable of type size_t, so that side effecting array dimensions are only
+		/// computed once.
+		static void hoistArrayDimension( std::list< Declaration * > & translationUnit );
+
+		void premutate( ObjectDecl * objectDecl );
+		DeclarationWithType * postmutate( ObjectDecl * objectDecl );
+		void premutate( FunctionDecl *functionDecl );
+		// should not traverse into any of these declarations to find objects
+		// that need to be constructed or destructed
+		void premutate( AggregateDecl * ) { visit_children = false; }
+		void premutate( NamedTypeDecl * ) { visit_children = false; }
+		void premutate( FunctionType * ) { visit_children = false; }
+
+		void hoist( Type * type );
+
+		Type::StorageClasses storageClasses;
+		bool inFunction = false;
+	};
+
 	void genInit( std::list< Declaration * > & translationUnit ) {
-		HoistArrayDimension::hoistArrayDimension( translationUnit );
+		if (!useNewAST) {
+			HoistArrayDimension::hoistArrayDimension( translationUnit );
+		}
+		else {
+			HoistArrayDimension_NoResolve::hoistArrayDimension( translationUnit );
+		}
 		fixReturnStatements( translationUnit );
 
@@ -196,9 +222,7 @@
 
 			// need to resolve array dimensions in order to accurately determine if constexpr
-			if (!useNewAST) {
-				ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
-				// array is variable-length when the dimension is not constexpr
-				arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
-			}
+			ResolvExpr::findSingleExpression( arrayType->dimension, Validate::SizeType->clone(), indexer );
+			// array is variable-length when the dimension is not constexpr
+			arrayType->isVarLen = ! isConstExpr( arrayType->dimension );
 			// don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
 			// xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
@@ -218,4 +242,52 @@
 
 	void HoistArrayDimension::premutate( FunctionDecl * ) {
+		GuardValue( inFunction );
+		inFunction = true;
+	}
+
+	// precompute array dimension expression, because constructor generation may duplicate it,
+	// which would be incorrect if it is a side-effecting computation.
+	void HoistArrayDimension_NoResolve::hoistArrayDimension( std::list< Declaration * > & translationUnit ) {
+		PassVisitor<HoistArrayDimension_NoResolve> hoister;
+		mutateAll( translationUnit, hoister );
+	}
+
+	void HoistArrayDimension_NoResolve::premutate( ObjectDecl * objectDecl ) {
+		GuardValue( storageClasses );
+		storageClasses = objectDecl->get_storageClasses();
+	}
+
+	DeclarationWithType * HoistArrayDimension_NoResolve::postmutate( ObjectDecl * objectDecl ) {
+		hoist( objectDecl->get_type() );
+		return objectDecl;
+	}
+
+	void HoistArrayDimension_NoResolve::hoist( Type * type ) {
+		// if in function, generate const size_t var
+		static UniqueName dimensionName( "_array_dim" );
+
+		// C doesn't allow variable sized arrays at global scope or for static variables, so don't hoist dimension.
+		if ( ! inFunction ) return;
+		if ( storageClasses.is_static ) return;
+
+		if ( ArrayType * arrayType = dynamic_cast< ArrayType * >( type ) ) {
+			if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
+			// don't need to hoist dimension if it's definitely pure - only need to if there's potential for side effects.
+			// xxx - hoisting has no side effects anyways, so don't skip since we delay resolve
+			// still try to detect constant expressions
+			if ( ! Tuples::maybeImpure( arrayType->dimension ) ) return;
+
+			ObjectDecl * arrayDimension = new ObjectDecl( dimensionName.newName(), storageClasses, LinkageSpec::C, 0, Validate::SizeType->clone(), new SingleInit( arrayType->get_dimension() ) );
+			arrayDimension->get_type()->set_const( true );
+
+			arrayType->set_dimension( new VariableExpr( arrayDimension ) );
+			declsToAddBefore.push_back( arrayDimension );
+
+			hoist( arrayType->get_base() );
+			return;
+		}
+	}
+
+	void HoistArrayDimension_NoResolve::premutate( FunctionDecl * ) {
 		GuardValue( inFunction );
 		inFunction = true;
