Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision 4c196473629eb845795ca16d36b6bd5e1e5dbcd1)
+++ src/InitTweak/GenInit.cc	(revision 83c7e3cf99240bd5d12e36be832622fd64f9f9a4)
@@ -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;
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 4c196473629eb845795ca16d36b6bd5e1e5dbcd1)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 83c7e3cf99240bd5d12e36be832622fd64f9f9a4)
@@ -905,5 +905,10 @@
 			// xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
 			// this means there exists ctor/assign functions with a tuple as first parameter.
-			funcFinder.find( untypedExpr->func, selfFinder.candidates.empty() ? ResolvMode::withAdjustment() : ResolvMode::withoutFailFast() );
+			ResolvMode mode = {
+				true, // adjust
+				!untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
+				selfFinder.candidates.empty() // failfast if other options are not found
+			};
+			funcFinder.find( untypedExpr->func, mode );
 			// short-circuit if no candidates
 			// if ( funcFinder.candidates.empty() ) return;
Index: src/ResolvExpr/ResolvMode.h
===================================================================
--- src/ResolvExpr/ResolvMode.h	(revision 4c196473629eb845795ca16d36b6bd5e1e5dbcd1)
+++ src/ResolvExpr/ResolvMode.h	(revision 83c7e3cf99240bd5d12e36be832622fd64f9f9a4)
@@ -23,9 +23,7 @@
 		const bool failFast;         ///< Fail on no resulting alternatives? [true]
 
-	private:
 		constexpr ResolvMode(bool a, bool p, bool ff) 
 		: adjust(a), prune(p), failFast(ff) {}
 
-	public:
 		/// Default settings
 		constexpr ResolvMode() : adjust(false), prune(true), failFast(true) {}
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 4c196473629eb845795ca16d36b6bd5e1e5dbcd1)
+++ src/SymTab/Validate.cc	(revision 83c7e3cf99240bd5d12e36be832622fd64f9f9a4)
@@ -271,5 +271,5 @@
 	};
 
-	struct ArrayLength : public WithIndexer {
+	struct InitializerLength {
 		/// for array types without an explicit length, compute the length and store it so that it
 		/// is known to the rest of the phases. For example,
@@ -282,4 +282,9 @@
 
 		void previsit( ObjectDecl * objDecl );
+	};
+
+	struct ArrayLength : public WithIndexer {
+		static void computeLength( std::list< Declaration * > & translationUnit );
+
 		void previsit( ArrayType * arrayType );
 	};
@@ -382,6 +387,10 @@
 					FixObjectType::fix, translationUnit);
 			}
-			Stats::Time::TimeCall("Array Length",
-				ArrayLength::computeLength, translationUnit);
+			Stats::Time::TimeCall("Initializer Length",
+				InitializerLength::computeLength, translationUnit);
+			if (!useNewAST) {
+				Stats::Time::TimeCall("Array Length",
+					ArrayLength::computeLength, translationUnit);
+			}
 			Stats::Time::TimeCall("Find Special Declarations",
 				Validate::findSpecialDecls, translationUnit);
@@ -1332,4 +1341,9 @@
 	}
 
+	void InitializerLength::computeLength( std::list< Declaration * > & translationUnit ) {
+		PassVisitor<InitializerLength> len;
+		acceptAll( translationUnit, len );
+	}
+
 	void ArrayLength::computeLength( std::list< Declaration * > & translationUnit ) {
 		PassVisitor<ArrayLength> len;
@@ -1337,5 +1351,5 @@
 	}
 
-	void ArrayLength::previsit( ObjectDecl * objDecl ) {
+	void InitializerLength::previsit( ObjectDecl * objDecl ) {
 		if ( ArrayType * at = dynamic_cast< ArrayType * >( objDecl->type ) ) {
 			if ( at->dimension ) return;
@@ -1347,14 +1361,12 @@
 
 	void ArrayLength::previsit( ArrayType * type ) {
-		if (!useNewAST) {
-			if ( type->dimension ) {
-				// need to resolve array dimensions early so that constructor code can correctly determine
-				// if a type is a VLA (and hence whether its elements need to be constructed)
-				ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
-
-				// must re-evaluate whether a type is a VLA, now that more information is available
-				// (e.g. the dimension may have been an enumerator, which was unknown prior to this step)
-				type->isVarLen = ! InitTweak::isConstExpr( type->dimension );
-			}
+		if ( type->dimension ) {
+			// need to resolve array dimensions early so that constructor code can correctly determine
+			// if a type is a VLA (and hence whether its elements need to be constructed)
+			ResolvExpr::findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
+
+			// must re-evaluate whether a type is a VLA, now that more information is available
+			// (e.g. the dimension may have been an enumerator, which was unknown prior to this step)
+			type->isVarLen = ! InitTweak::isConstExpr( type->dimension );
 		}
 	}
