Index: src/InitTweak/FixGlobalInit.cc
===================================================================
--- src/InitTweak/FixGlobalInit.cc	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,113 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// FixGlobalInit.cc --
-//
-// Author           : Rob Schluntz
-// Created On       : Mon May 04 15:14:56 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:41:10 2019
-// Update Count     : 19
-//
-
-#include "FixGlobalInit.h"
-
-#include <cassert>                 // for assert
-#include <stddef.h>                // for NULL
-#include <algorithm>               // for replace_if
-
-#include "AST/Expr.hpp"
-#include "AST/Node.hpp"
-#include "AST/Pass.hpp"
-#include "Common/UniqueName.h"     // for UniqueName
-#include "InitTweak.h"             // for isIntrinsicSingleArgCallStmt
-
-namespace InitTweak {
-
-namespace {
-
-class GlobalFixer : public ast::WithShortCircuiting {
-public:
-	void previsit(const ast::ObjectDecl *);
-	void previsit(const ast::FunctionDecl *) { visit_children = false; }
-	void previsit(const ast::StructDecl *) { visit_children = false; }
-	void previsit(const ast::UnionDecl *) { visit_children = false; }
-	void previsit(const ast::EnumDecl *) { visit_children = false; }
-	void previsit(const ast::TraitDecl *) { visit_children = false; }
-	void previsit(const ast::TypeDecl *) { visit_children = false; }
-
-	std::list< ast::ptr<ast::Stmt> > initStmts;
-	std::list< ast::ptr<ast::Stmt> > destroyStmts;
-};
-
-void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) {
-	auto mutDecl = mutate(objDecl);
-	assertf(mutDecl == objDecl, "Global object decl must be unique");
-	auto ctorInit = objDecl->init.as<ast::ConstructorInit>();
-	if ( nullptr == ctorInit ) return;
-
-	// a decision should have been made by the resolver, so ctor and init are not both non-NULL
-	assert( !ctorInit->ctor || !ctorInit->init );
-
-	const ast::Stmt * dtor = ctorInit->dtor;
-	if ( dtor && !isIntrinsicSingleArgCallStmt( dtor ) ) {
-		// don't need to call intrinsic dtor, because it does nothing, but
-		// non-intrinsic dtors must be called
-		destroyStmts.push_front( dtor );
-	} // if
-	if ( const ast::Stmt * ctor = ctorInit->ctor ) {
-		addDataSectionAttribute(mutDecl);
-		initStmts.push_back( ctor );
-		mutDecl->init = nullptr;
-	} else if ( const ast::Init * init = ctorInit->init ) {
-		mutDecl->init = init;
-	} else {
-		// no constructor and no initializer, which is okay
-		mutDecl->init = nullptr;
-	}
-}
-
-} // namespace
-
-void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
-	ast::Pass<GlobalFixer> fixer;
-	accept_all(translationUnit, fixer);
-
-	// Say these magic declarations come at the end of the file.
-	CodeLocation const & location = translationUnit.decls.back()->location;
-
-	if ( !fixer.core.initStmts.empty() ) {
-		std::vector<ast::ptr<ast::Expr>> ctorParams;
-		if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
-		auto initFunction = new ast::FunctionDecl(location,
-			"__global_init__", {}, {}, {}, {},
-			new ast::CompoundStmt(location, std::move(fixer.core.initStmts)),
-			ast::Storage::Static, ast::Linkage::C,
-			{new ast::Attribute("constructor", std::move(ctorParams))});
-
-		translationUnit.decls.emplace_back( initFunction );
-	} // if
-
-	if ( !fixer.core.destroyStmts.empty() ) {
-		std::vector<ast::ptr<ast::Expr>> dtorParams;
-		if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
-		auto destroyFunction = new ast::FunctionDecl( location,
-			"__global_destroy__", {}, {}, {}, {},
-			new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)),
-			ast::Storage::Static, ast::Linkage::C,
-			{new ast::Attribute("destructor", std::move(dtorParams))});
-
-		translationUnit.decls.emplace_back(destroyFunction);
-	} // if
-}
-
-} // namespace InitTweak
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/InitTweak/FixGlobalInit.cpp
===================================================================
--- src/InitTweak/FixGlobalInit.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/InitTweak/FixGlobalInit.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,113 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// FixGlobalInit.cpp --
+//
+// Author           : Rob Schluntz
+// Created On       : Mon May 04 15:14:56 2016
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri Dec 13 23:41:10 2019
+// Update Count     : 19
+//
+
+#include "FixGlobalInit.hpp"
+
+#include <cassert>                 // for assert
+#include <stddef.h>                // for NULL
+#include <algorithm>               // for replace_if
+
+#include "AST/Expr.hpp"
+#include "AST/Node.hpp"
+#include "AST/Pass.hpp"
+#include "Common/UniqueName.hpp"   // for UniqueName
+#include "InitTweak.hpp"           // for isIntrinsicSingleArgCallStmt
+
+namespace InitTweak {
+
+namespace {
+
+class GlobalFixer : public ast::WithShortCircuiting {
+public:
+	void previsit(const ast::ObjectDecl *);
+	void previsit(const ast::FunctionDecl *) { visit_children = false; }
+	void previsit(const ast::StructDecl *) { visit_children = false; }
+	void previsit(const ast::UnionDecl *) { visit_children = false; }
+	void previsit(const ast::EnumDecl *) { visit_children = false; }
+	void previsit(const ast::TraitDecl *) { visit_children = false; }
+	void previsit(const ast::TypeDecl *) { visit_children = false; }
+
+	std::list< ast::ptr<ast::Stmt> > initStmts;
+	std::list< ast::ptr<ast::Stmt> > destroyStmts;
+};
+
+void GlobalFixer::previsit(const ast::ObjectDecl * objDecl) {
+	auto mutDecl = mutate(objDecl);
+	assertf(mutDecl == objDecl, "Global object decl must be unique");
+	auto ctorInit = objDecl->init.as<ast::ConstructorInit>();
+	if ( nullptr == ctorInit ) return;
+
+	// a decision should have been made by the resolver, so ctor and init are not both non-NULL
+	assert( !ctorInit->ctor || !ctorInit->init );
+
+	const ast::Stmt * dtor = ctorInit->dtor;
+	if ( dtor && !isIntrinsicSingleArgCallStmt( dtor ) ) {
+		// don't need to call intrinsic dtor, because it does nothing, but
+		// non-intrinsic dtors must be called
+		destroyStmts.push_front( dtor );
+	} // if
+	if ( const ast::Stmt * ctor = ctorInit->ctor ) {
+		addDataSectionAttribute(mutDecl);
+		initStmts.push_back( ctor );
+		mutDecl->init = nullptr;
+	} else if ( const ast::Init * init = ctorInit->init ) {
+		mutDecl->init = init;
+	} else {
+		// no constructor and no initializer, which is okay
+		mutDecl->init = nullptr;
+	}
+}
+
+} // namespace
+
+void fixGlobalInit(ast::TranslationUnit & translationUnit, bool inLibrary) {
+	ast::Pass<GlobalFixer> fixer;
+	accept_all(translationUnit, fixer);
+
+	// Say these magic declarations come at the end of the file.
+	CodeLocation const & location = translationUnit.decls.back()->location;
+
+	if ( !fixer.core.initStmts.empty() ) {
+		std::vector<ast::ptr<ast::Expr>> ctorParams;
+		if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
+		auto initFunction = new ast::FunctionDecl(location,
+			"__global_init__", {}, {}, {}, {},
+			new ast::CompoundStmt(location, std::move(fixer.core.initStmts)),
+			ast::Storage::Static, ast::Linkage::C,
+			{new ast::Attribute("constructor", std::move(ctorParams))});
+
+		translationUnit.decls.emplace_back( initFunction );
+	} // if
+
+	if ( !fixer.core.destroyStmts.empty() ) {
+		std::vector<ast::ptr<ast::Expr>> dtorParams;
+		if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
+		auto destroyFunction = new ast::FunctionDecl( location,
+			"__global_destroy__", {}, {}, {}, {},
+			new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)),
+			ast::Storage::Static, ast::Linkage::C,
+			{new ast::Attribute("destructor", std::move(dtorParams))});
+
+		translationUnit.decls.emplace_back(destroyFunction);
+	} // if
+}
+
+} // namespace InitTweak
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/InitTweak/FixGlobalInit.h
===================================================================
--- src/InitTweak/FixGlobalInit.h	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,35 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// FixGlobalInit.h --
-//
-// Author           : Rob Schluntz
-// Created On       : Mon May 04 15:14:56 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:30:54 2017
-// Update Count     : 3
-//
-
-#pragma once
-
-namespace ast {
-	class TranslationUnit;
-}
-
-namespace InitTweak {
-
-/// Moves global initialization into an _init function that is unique to the translation unit.
-/// Sets the priority of the initialization function depending on whether the initialization
-/// function is for library code.
-void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary );
-
-} // namespace
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/InitTweak/FixGlobalInit.hpp
===================================================================
--- src/InitTweak/FixGlobalInit.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/InitTweak/FixGlobalInit.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,35 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// FixGlobalInit.hpp --
+//
+// Author           : Rob Schluntz
+// Created On       : Mon May 04 15:14:56 2016
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Jul 22 09:30:54 2017
+// Update Count     : 3
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace InitTweak {
+
+/// Moves global initialization into an _init function that is unique to the translation unit.
+/// Sets the priority of the initialization function depending on whether the initialization
+/// function is for library code.
+void fixGlobalInit( ast::TranslationUnit & translationUnit, bool inLibrary );
+
+} // namespace
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/InitTweak/FixInit.cpp
===================================================================
--- src/InitTweak/FixInit.cpp	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ src/InitTweak/FixInit.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -1,3 +1,3 @@
-#include "FixInit.h"
+#include "FixInit.hpp"
 
 #include <stddef.h>                    // for NULL
@@ -22,13 +22,13 @@
 #include "AST/SymbolTable.hpp"
 #include "AST/Type.hpp"
-#include "CodeGen/OperatorTable.h"     // for isConstructor, isCtorDtor, isD...
-#include "Common/SemanticError.h"      // for SemanticError
+#include "CodeGen/OperatorTable.hpp"   // for isConstructor, isCtorDtor, isD...
+#include "Common/SemanticError.hpp"    // for SemanticError
 #include "Common/ToString.hpp"         // for toCString
-#include "Common/UniqueName.h"         // for UniqueName
-#include "FixGlobalInit.h"             // for fixGlobalInit
-#include "GenInit.h"                   // for genCtorDtor
-#include "GenPoly/GenPoly.h"           // for getFunctionType
-#include "ResolvExpr/Resolver.h"       // for findVoidExpression
-#include "ResolvExpr/Unify.h"          // for typesCompatible
+#include "Common/UniqueName.hpp"       // for UniqueName
+#include "FixGlobalInit.hpp"           // for fixGlobalInit
+#include "GenInit.hpp"                 // for genCtorDtor
+#include "GenPoly/GenPoly.hpp"         // for getFunctionType
+#include "ResolvExpr/Resolver.hpp"     // for findVoidExpression
+#include "ResolvExpr/Unify.hpp"        // for typesCompatible
 #include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
 
Index: src/InitTweak/FixInit.h
===================================================================
--- src/InitTweak/FixInit.h	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,33 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// FixInit.h --
-//
-// Author           : Rob Schluntz
-// Created On       : Wed Jan 13 16:29:30 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Feb 16 07:54:50 2020
-// Update Count     : 8
-//
-
-#pragma once
-
-namespace ast {
-	class TranslationUnit;
-}
-
-namespace InitTweak {
-
-/// Replace constructor initializers with expression statements and unwrap basic C-style initializers.
-void fix( ast::TranslationUnit & translationUnit, bool inLibrary);
-
-} // namespace
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/InitTweak/FixInit.hpp
===================================================================
--- src/InitTweak/FixInit.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/InitTweak/FixInit.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,33 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// FixInit.hpp --
+//
+// Author           : Rob Schluntz
+// Created On       : Wed Jan 13 16:29:30 2016
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sun Feb 16 07:54:50 2020
+// Update Count     : 8
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace InitTweak {
+
+/// Replace constructor initializers with expression statements and unwrap basic C-style initializers.
+void fix( ast::TranslationUnit & translationUnit, bool inLibrary);
+
+} // namespace
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,368 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// GenInit.cc -- Generate initializers, and other stuff.
-//
-// Author           : Rob Schluntz
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Mon Oct 25 13:53:00 2021
-// Update Count     : 186
-//
-#include "GenInit.h"
-
-#include <stddef.h>                    // for NULL
-#include <algorithm>                   // for any_of
-#include <cassert>                     // for assert, strict_dynamic_cast, assertf
-#include <deque>
-#include <iterator>                    // for back_inserter, inserter, back_inse...
-#include <list>                        // for _List_iterator, list
-
-#include "AST/Decl.hpp"
-#include "AST/Init.hpp"
-#include "AST/Pass.hpp"
-#include "AST/Node.hpp"
-#include "AST/Stmt.hpp"
-#include "CompilationState.hpp"
-#include "CodeGen/OperatorTable.h"
-#include "Common/SemanticError.h"      // for SemanticError
-#include "Common/ToString.hpp"         // for toCString
-#include "Common/UniqueName.h"         // for UniqueName
-#include "Common/utility.h"            // for ValueGuard, maybeClone
-#include "GenPoly/GenPoly.h"           // for getFunctionType, isPolyType
-#include "GenPoly/ScopedSet.h"         // for ScopedSet, ScopedSet<>::const_iter...
-#include "InitTweak.h"                 // for isConstExpr, InitExpander, checkIn...
-#include "ResolvExpr/Resolver.h"
-#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
-#include "SymTab/Mangler.h"            // for Mangler
-#include "Tuples/Tuples.h"             // for maybeImpure
-#include "Validate/FindSpecialDecls.h" // for SizeType
-
-namespace InitTweak {
-
-namespace {
-
-	// Outer pass finds declarations, for their type could wrap a type that needs hoisting
-	struct HoistArrayDimension_NoResolve final :
-			public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
-			public ast::WithGuards, public ast::WithConstTranslationUnit,
-			public ast::WithVisitorRef<HoistArrayDimension_NoResolve>,
-			public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> {
-
-		// Inner pass looks within a type, for a part that depends on an expression
-		struct HoistDimsFromTypes final :
-				public ast::WithShortCircuiting, public ast::WithGuards {
-
-			HoistArrayDimension_NoResolve * outer;
-			HoistDimsFromTypes( HoistArrayDimension_NoResolve * outer ) : outer(outer) {}
-
-			// Only intended for visiting through types.
-			// Tolerate, and short-circuit at, the dimension expression of an array type.
-			//    (We'll operate on the dimension expression of an array type directly
-			//    from the parent type, not by visiting through it)
-			// Look inside type exprs.
-			void previsit( const ast::Node * ) {
-				assert( false && "unsupported node type" );
-			};
-			const ast::Expr * allowedExpr = nullptr;
-			void previsit( const ast::Type * ) {
-				GuardValue( allowedExpr ) = nullptr;
-			}
-			void previsit( const ast::ArrayType * t ) {
-				GuardValue( allowedExpr ) = t->dimension.get();
-			}
-			void previsit( const ast::PointerType * t ) {
-				GuardValue( allowedExpr ) = t->dimension.get();
-			}
-			void previsit( const ast::TypeofType * t ) {
-				GuardValue( allowedExpr ) = t->expr.get();
-			}
-			void previsit( const ast::Expr * e ) {
-				assert( e == allowedExpr &&
-				    "only expecting to visit exprs that are dimension exprs or typeof(-) inner exprs" );
-
-				// Skip the tolerated expressions
-				visit_children = false;
-			}
-			void previsit( const ast::TypeExpr * ) {}
-
-			const ast::Type * postvisit(
-					const ast::ArrayType * arrayType ) {
-				static UniqueName dimensionName( "_array_dim" );
-
-				if ( nullptr == arrayType->dimension ) {  // if no dimension is given, don't presume to invent one
-					return arrayType;
-				}
-
-				// find size_t; use it as the type for a dim expr
-				ast::ptr<ast::Type> dimType = outer->transUnit().global.sizeType;
-				assert( dimType );
-				add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
-
-				// Special-case handling: leave the user's dimension expression alone
-				// - requires the user to have followed a careful convention
-				// - may apply to extremely simple applications, but only as windfall
-				// - users of advanced applications will be following the convention on purpose
-				// - CFA maintainers must protect the criteria against leaving too much alone
-
-				// Actual leave-alone cases following are conservative approximations of "cannot vary"
-
-				// Leave alone: literals and enum constants
-				if ( dynamic_cast< const ast::ConstantExpr * >( arrayType->dimension.get() ) ) {
-					return arrayType;
-				}
-
-				// Leave alone: direct use of an object declared to be const
-				const ast::NameExpr * dimn = dynamic_cast< const ast::NameExpr * >( arrayType->dimension.get() );
-				if ( dimn ) {
-					std::vector<ast::SymbolTable::IdData> dimnDefs = outer->symtab.lookupId( dimn->name );
-					if ( dimnDefs.size() == 1 ) {
-						const ast::DeclWithType * dimnDef = dimnDefs[0].id.get();
-						assert( dimnDef && "symbol table binds a name to nothing" );
-						const ast::ObjectDecl * dimOb = dynamic_cast< const ast::ObjectDecl * >( dimnDef );
-						if( dimOb ) {
-							const ast::Type * dimTy = dimOb->type.get();
-							assert( dimTy && "object declaration bearing no type" );
-							// must not hoist some: size_t
-							// must hoist all: pointers and references
-							// the analysis is conservative; BasicType is a simple approximation
-							if ( dynamic_cast< const ast::BasicType * >( dimTy ) ||
-							     dynamic_cast< const ast::SueInstType<ast::EnumDecl> * >( dimTy ) ) {
-								if ( dimTy->is_const() ) {
-									// The dimension is certainly re-evaluable, giving the same answer each time.
-									// Our user might be hoping to write the array type in multiple places, having them unify.
-									// Leave the type alone.
-
-									// We believe the new criterion leaves less alone than the old criterion.
-									// Thus, the old criterion should have left the current case alone.
-									// Catch cases that weren't thought through.
-									assert( !Tuples::maybeImpure( arrayType->dimension ) );
-
-									return arrayType;
-								}
-							};
-						}
-					}
-				}
-
-				// Leave alone: any sizeof expression (answer cannot vary during current lexical scope)
-				const ast::SizeofExpr * sz = dynamic_cast< const ast::SizeofExpr * >( arrayType->dimension.get() );
-				if ( sz ) {
-					return arrayType;
-				}
-
-				// General-case handling: change the array-type's dim expr (hoist the user-given content out of the type)
-				// - always safe
-				// - user-unnoticeable in common applications (benign noise in -CFA output)
-				// - may annoy a responsible user of advanced applications (but they can work around)
-				// - protects against misusing advanced features
-				//
-				// The hoist, by example, is:
-				// FROM USER:  float a[ rand() ];
-				// TO GCC:     const size_t __len_of_a = rand(); float a[ __len_of_a ];
-
-				ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
-					arrayType->dimension->location,
-					dimensionName.newName(),
-					dimType,
-					new ast::SingleInit(
-						arrayType->dimension->location,
-						arrayType->dimension
-					)
-				);
-
-				ast::ArrayType * mutType = ast::mutate( arrayType );
-				mutType->dimension = new ast::VariableExpr(
-						arrayDimension->location, arrayDimension );
-				outer->declsToAddBefore.push_back( arrayDimension );
-
-				return mutType;
-			}  // postvisit( const ast::ArrayType * )
-		}; // struct HoistDimsFromTypes
-
-		ast::Storage::Classes storageClasses;
-		void previsit(
-				const ast::ObjectDecl * decl ) {
-			GuardValue( storageClasses ) = decl->storage;
-		}
-
-		const ast::DeclWithType * postvisit(
-				const ast::ObjectDecl * objectDecl ) {
-
-			if ( !isInFunction() || storageClasses.is_static ) {
-				return objectDecl;
-			}
-
-			const ast::Type * mid = objectDecl->type;
-
-			ast::Pass<HoistDimsFromTypes> hoist{this};
-			const ast::Type * result = mid->accept( hoist );
-
-			return mutate_field( objectDecl, &ast::ObjectDecl::type, result );
-		}
-	};
-
-	struct ReturnFixer final :
-			public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting {
-		void previsit( const ast::FunctionDecl * decl );
-		const ast::ReturnStmt * previsit( const ast::ReturnStmt * stmt );
-	private:
-		const ast::FunctionDecl * funcDecl = nullptr;
-	};
-
-	void ReturnFixer::previsit( const ast::FunctionDecl * decl ) {
-		if (decl->linkage == ast::Linkage::Intrinsic) visit_children = false;
-		GuardValue( funcDecl ) = decl;
-	}
-
-	const ast::ReturnStmt * ReturnFixer::previsit(
-			const ast::ReturnStmt * stmt ) {
-		auto & returns = funcDecl->returns;
-		assert( returns.size() < 2 );
-		// Hands off if the function returns a reference.
-		// Don't allocate a temporary if the address is returned.
-		if ( stmt->expr && 1 == returns.size() ) {
-			ast::ptr<ast::DeclWithType> retDecl = returns.front();
-			if ( isConstructable( retDecl->get_type() ) ) {
-				// Explicitly construct the return value using the return
-				// expression and the retVal object.
-				assertf( "" != retDecl->name,
-					"Function %s has unnamed return value.\n",
-					funcDecl->name.c_str() );
-
-				auto retVal = retDecl.strict_as<ast::ObjectDecl>();
-				if ( auto varExpr = stmt->expr.as<ast::VariableExpr>() ) {
-					// Check if the return statement is already set up.
-					if ( varExpr->var == retVal ) return stmt;
-				}
-				const ast::Stmt * ctorStmt = genCtorDtor(
-					retVal->location, "?{}", retVal, stmt->expr );
-				assertf( ctorStmt,
-					"ReturnFixer: genCtorDtor returned nullptr: %s / %s",
-					toString( retVal ).c_str(),
-					toString( stmt->expr ).c_str() );
-				stmtsToAddBefore.push_back( ctorStmt );
-
-				// Return the retVal object.
-				ast::ReturnStmt * mutStmt = ast::mutate( stmt );
-				mutStmt->expr = new ast::VariableExpr(
-					stmt->location, retDecl );
-				return mutStmt;
-			}
-		}
-		return stmt;
-	}
-
-} // namespace
-
-void genInit( ast::TranslationUnit & transUnit ) {
-	ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit );
-	ast::Pass<ReturnFixer>::run( transUnit );
-}
-
-void fixReturnStatements( ast::TranslationUnit & transUnit ) {
-	ast::Pass<ReturnFixer>::run( transUnit );
-}
-
-bool ManagedTypes::isManaged( const ast::Type * type ) const {
-	// references are never constructed
-	if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
-	if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
-		// tuple is also managed if any of its components are managed
-		for (auto & component : tupleType->types) {
-			if (isManaged(component)) return true;
-		}
-	}
-	// need to clear and reset qualifiers when determining if a type is managed
-	// ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
-	auto tmp = shallowCopy(type);
-	tmp->qualifiers = {};
-	// delete tmp at return
-	ast::ptr<ast::Type> guard = tmp;
-	// a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
-	return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
-}
-
-bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const {
-	const ast::Type * type = objDecl->type;
-	while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
-		// must always construct VLAs with an initializer, since this is an error in C
-		if ( at->isVarLen && objDecl->init ) return true;
-		type = at->base;
-	}
-	return isManaged( type );
-}
-
-void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) {
-	// if this function is a user-defined constructor or destructor, mark down the type as "managed"
-	if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
-		auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
-		assert( ! params.empty() );
-		// Type * type = InitTweak::getPointerBase( params.front() );
-		// assert( type );
-		managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
-	}
-}
-
-void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) {
-	// don't construct members, but need to take note if there is a managed member,
-	// because that means that this type is also managed
-	for ( auto & member : aggregateDecl->members ) {
-		if ( auto field = member.as<ast::ObjectDecl>() ) {
-			if ( isManaged( field ) ) {
-				// generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
-				// polymorphic constructors make generic types managed types
-				ast::StructInstType inst( aggregateDecl );
-				managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
-				break;
-			}
-		}
-	}
-}
-
-void ManagedTypes::beginScope() { managedTypes.beginScope(); }
-void ManagedTypes::endScope() { managedTypes.endScope(); }
-
-const ast::Stmt * genCtorDtor( const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg ) {
-	assertf(objDecl, "genCtorDtor passed null objDecl");
-	InitExpander srcParam(arg);
-	return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
-}
-
-ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) {
-	// call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each
-	// constructable object
-	InitExpander srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
-	ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
-
-	ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
-		srcParam, dstParam, loc, "?{}", objDecl );
-	ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
-		nullParam, dstParam, loc, "^?{}", objDecl,
-		SymTab::LoopBackward );
-
-	// check that either both ctor and dtor are present, or neither
-	assert( (bool)ctor == (bool)dtor );
-
-	if ( ctor ) {
-		// need to remember init expression, in case no ctors exist. If ctor does exist, want to
-		// use ctor expression instead of init.
-		ctor.strict_as< ast::ImplicitCtorDtorStmt >();
-		dtor.strict_as< ast::ImplicitCtorDtorStmt >();
-
-		return new ast::ConstructorInit{ loc, ctor, dtor, objDecl->init };
-	}
-
-	return nullptr;
-}
-
-} // namespace InitTweak
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/InitTweak/GenInit.cpp
===================================================================
--- src/InitTweak/GenInit.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/InitTweak/GenInit.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,367 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// GenInit.cpp -- Generate initializers, and other stuff.
+//
+// Author           : Rob Schluntz
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Oct 25 13:53:00 2021
+// Update Count     : 186
+//
+#include "GenInit.hpp"
+
+#include <stddef.h>                    // for NULL
+#include <algorithm>                   // for any_of
+#include <cassert>                     // for assert, strict_dynamic_cast, assertf
+#include <deque>
+#include <iterator>                    // for back_inserter, inserter, back_inse...
+#include <list>                        // for _List_iterator, list
+
+#include "AST/Decl.hpp"
+#include "AST/Init.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Node.hpp"
+#include "AST/Stmt.hpp"
+#include "CompilationState.hpp"
+#include "CodeGen/OperatorTable.hpp"
+#include "Common/SemanticError.hpp"    // for SemanticError
+#include "Common/ToString.hpp"         // for toCString
+#include "Common/UniqueName.hpp"       // for UniqueName
+#include "Common/Utility.hpp"          // for ValueGuard, maybeClone
+#include "GenPoly/GenPoly.hpp"         // for getFunctionType, isPolyType
+#include "GenPoly/ScopedSet.hpp"       // for ScopedSet, ScopedSet<>::const_iter...
+#include "InitTweak.hpp"               // for isConstExpr, InitExpander, checkIn...
+#include "ResolvExpr/Resolver.hpp"
+#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
+#include "SymTab/Mangler.hpp"          // for Mangler
+#include "Tuples/Tuples.hpp"           // for maybeImpure
+
+namespace InitTweak {
+
+namespace {
+
+	// Outer pass finds declarations, for their type could wrap a type that needs hoisting
+	struct HoistArrayDimension_NoResolve final :
+			public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
+			public ast::WithGuards, public ast::WithConstTranslationUnit,
+			public ast::WithVisitorRef<HoistArrayDimension_NoResolve>,
+			public ast::WithSymbolTableX<ast::SymbolTable::ErrorDetection::IgnoreErrors> {
+
+		// Inner pass looks within a type, for a part that depends on an expression
+		struct HoistDimsFromTypes final :
+				public ast::WithShortCircuiting, public ast::WithGuards {
+
+			HoistArrayDimension_NoResolve * outer;
+			HoistDimsFromTypes( HoistArrayDimension_NoResolve * outer ) : outer(outer) {}
+
+			// Only intended for visiting through types.
+			// Tolerate, and short-circuit at, the dimension expression of an array type.
+			//    (We'll operate on the dimension expression of an array type directly
+			//    from the parent type, not by visiting through it)
+			// Look inside type exprs.
+			void previsit( const ast::Node * ) {
+				assert( false && "unsupported node type" );
+			};
+			const ast::Expr * allowedExpr = nullptr;
+			void previsit( const ast::Type * ) {
+				GuardValue( allowedExpr ) = nullptr;
+			}
+			void previsit( const ast::ArrayType * t ) {
+				GuardValue( allowedExpr ) = t->dimension.get();
+			}
+			void previsit( const ast::PointerType * t ) {
+				GuardValue( allowedExpr ) = t->dimension.get();
+			}
+			void previsit( const ast::TypeofType * t ) {
+				GuardValue( allowedExpr ) = t->expr.get();
+			}
+			void previsit( const ast::Expr * e ) {
+				assert( e == allowedExpr &&
+				    "only expecting to visit exprs that are dimension exprs or typeof(-) inner exprs" );
+
+				// Skip the tolerated expressions
+				visit_children = false;
+			}
+			void previsit( const ast::TypeExpr * ) {}
+
+			const ast::Type * postvisit(
+					const ast::ArrayType * arrayType ) {
+				static UniqueName dimensionName( "_array_dim" );
+
+				if ( nullptr == arrayType->dimension ) {  // if no dimension is given, don't presume to invent one
+					return arrayType;
+				}
+
+				// find size_t; use it as the type for a dim expr
+				ast::ptr<ast::Type> dimType = outer->transUnit().global.sizeType;
+				assert( dimType );
+				add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
+
+				// Special-case handling: leave the user's dimension expression alone
+				// - requires the user to have followed a careful convention
+				// - may apply to extremely simple applications, but only as windfall
+				// - users of advanced applications will be following the convention on purpose
+				// - CFA maintainers must protect the criteria against leaving too much alone
+
+				// Actual leave-alone cases following are conservative approximations of "cannot vary"
+
+				// Leave alone: literals and enum constants
+				if ( dynamic_cast< const ast::ConstantExpr * >( arrayType->dimension.get() ) ) {
+					return arrayType;
+				}
+
+				// Leave alone: direct use of an object declared to be const
+				const ast::NameExpr * dimn = dynamic_cast< const ast::NameExpr * >( arrayType->dimension.get() );
+				if ( dimn ) {
+					std::vector<ast::SymbolTable::IdData> dimnDefs = outer->symtab.lookupId( dimn->name );
+					if ( dimnDefs.size() == 1 ) {
+						const ast::DeclWithType * dimnDef = dimnDefs[0].id.get();
+						assert( dimnDef && "symbol table binds a name to nothing" );
+						const ast::ObjectDecl * dimOb = dynamic_cast< const ast::ObjectDecl * >( dimnDef );
+						if( dimOb ) {
+							const ast::Type * dimTy = dimOb->type.get();
+							assert( dimTy && "object declaration bearing no type" );
+							// must not hoist some: size_t
+							// must hoist all: pointers and references
+							// the analysis is conservative; BasicType is a simple approximation
+							if ( dynamic_cast< const ast::BasicType * >( dimTy ) ||
+							     dynamic_cast< const ast::SueInstType<ast::EnumDecl> * >( dimTy ) ) {
+								if ( dimTy->is_const() ) {
+									// The dimension is certainly re-evaluable, giving the same answer each time.
+									// Our user might be hoping to write the array type in multiple places, having them unify.
+									// Leave the type alone.
+
+									// We believe the new criterion leaves less alone than the old criterion.
+									// Thus, the old criterion should have left the current case alone.
+									// Catch cases that weren't thought through.
+									assert( !Tuples::maybeImpure( arrayType->dimension ) );
+
+									return arrayType;
+								}
+							};
+						}
+					}
+				}
+
+				// Leave alone: any sizeof expression (answer cannot vary during current lexical scope)
+				const ast::SizeofExpr * sz = dynamic_cast< const ast::SizeofExpr * >( arrayType->dimension.get() );
+				if ( sz ) {
+					return arrayType;
+				}
+
+				// General-case handling: change the array-type's dim expr (hoist the user-given content out of the type)
+				// - always safe
+				// - user-unnoticeable in common applications (benign noise in -CFA output)
+				// - may annoy a responsible user of advanced applications (but they can work around)
+				// - protects against misusing advanced features
+				//
+				// The hoist, by example, is:
+				// FROM USER:  float a[ rand() ];
+				// TO GCC:     const size_t __len_of_a = rand(); float a[ __len_of_a ];
+
+				ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
+					arrayType->dimension->location,
+					dimensionName.newName(),
+					dimType,
+					new ast::SingleInit(
+						arrayType->dimension->location,
+						arrayType->dimension
+					)
+				);
+
+				ast::ArrayType * mutType = ast::mutate( arrayType );
+				mutType->dimension = new ast::VariableExpr(
+						arrayDimension->location, arrayDimension );
+				outer->declsToAddBefore.push_back( arrayDimension );
+
+				return mutType;
+			}  // postvisit( const ast::ArrayType * )
+		}; // struct HoistDimsFromTypes
+
+		ast::Storage::Classes storageClasses;
+		void previsit(
+				const ast::ObjectDecl * decl ) {
+			GuardValue( storageClasses ) = decl->storage;
+		}
+
+		const ast::DeclWithType * postvisit(
+				const ast::ObjectDecl * objectDecl ) {
+
+			if ( !isInFunction() || storageClasses.is_static ) {
+				return objectDecl;
+			}
+
+			const ast::Type * mid = objectDecl->type;
+
+			ast::Pass<HoistDimsFromTypes> hoist{this};
+			const ast::Type * result = mid->accept( hoist );
+
+			return mutate_field( objectDecl, &ast::ObjectDecl::type, result );
+		}
+	};
+
+	struct ReturnFixer final :
+			public ast::WithStmtsToAdd<>, ast::WithGuards, ast::WithShortCircuiting {
+		void previsit( const ast::FunctionDecl * decl );
+		const ast::ReturnStmt * previsit( const ast::ReturnStmt * stmt );
+	private:
+		const ast::FunctionDecl * funcDecl = nullptr;
+	};
+
+	void ReturnFixer::previsit( const ast::FunctionDecl * decl ) {
+		if (decl->linkage == ast::Linkage::Intrinsic) visit_children = false;
+		GuardValue( funcDecl ) = decl;
+	}
+
+	const ast::ReturnStmt * ReturnFixer::previsit(
+			const ast::ReturnStmt * stmt ) {
+		auto & returns = funcDecl->returns;
+		assert( returns.size() < 2 );
+		// Hands off if the function returns a reference.
+		// Don't allocate a temporary if the address is returned.
+		if ( stmt->expr && 1 == returns.size() ) {
+			ast::ptr<ast::DeclWithType> retDecl = returns.front();
+			if ( isConstructable( retDecl->get_type() ) ) {
+				// Explicitly construct the return value using the return
+				// expression and the retVal object.
+				assertf( "" != retDecl->name,
+					"Function %s has unnamed return value.\n",
+					funcDecl->name.c_str() );
+
+				auto retVal = retDecl.strict_as<ast::ObjectDecl>();
+				if ( auto varExpr = stmt->expr.as<ast::VariableExpr>() ) {
+					// Check if the return statement is already set up.
+					if ( varExpr->var == retVal ) return stmt;
+				}
+				const ast::Stmt * ctorStmt = genCtorDtor(
+					retVal->location, "?{}", retVal, stmt->expr );
+				assertf( ctorStmt,
+					"ReturnFixer: genCtorDtor returned nullptr: %s / %s",
+					toString( retVal ).c_str(),
+					toString( stmt->expr ).c_str() );
+				stmtsToAddBefore.push_back( ctorStmt );
+
+				// Return the retVal object.
+				ast::ReturnStmt * mutStmt = ast::mutate( stmt );
+				mutStmt->expr = new ast::VariableExpr(
+					stmt->location, retDecl );
+				return mutStmt;
+			}
+		}
+		return stmt;
+	}
+
+} // namespace
+
+void genInit( ast::TranslationUnit & transUnit ) {
+	ast::Pass<HoistArrayDimension_NoResolve>::run( transUnit );
+	ast::Pass<ReturnFixer>::run( transUnit );
+}
+
+void fixReturnStatements( ast::TranslationUnit & transUnit ) {
+	ast::Pass<ReturnFixer>::run( transUnit );
+}
+
+bool ManagedTypes::isManaged( const ast::Type * type ) const {
+	// references are never constructed
+	if ( dynamic_cast< const ast::ReferenceType * >( type ) ) return false;
+	if ( auto tupleType = dynamic_cast< const ast::TupleType * > ( type ) ) {
+		// tuple is also managed if any of its components are managed
+		for (auto & component : tupleType->types) {
+			if (isManaged(component)) return true;
+		}
+	}
+	// need to clear and reset qualifiers when determining if a type is managed
+	// ValueGuard< Type::Qualifiers > qualifiers( type->get_qualifiers() );
+	auto tmp = shallowCopy(type);
+	tmp->qualifiers = {};
+	// delete tmp at return
+	ast::ptr<ast::Type> guard = tmp;
+	// a type is managed if it appears in the map of known managed types, or if it contains any polymorphism (is a type variable or generic type containing a type variable)
+	return managedTypes.find( Mangle::mangle( tmp, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) ) != managedTypes.end() || GenPoly::isPolyType( tmp );
+}
+
+bool ManagedTypes::isManaged( const ast::ObjectDecl * objDecl ) const {
+	const ast::Type * type = objDecl->type;
+	while ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
+		// must always construct VLAs with an initializer, since this is an error in C
+		if ( at->isVarLen && objDecl->init ) return true;
+		type = at->base;
+	}
+	return isManaged( type );
+}
+
+void ManagedTypes::handleDWT( const ast::DeclWithType * dwt ) {
+	// if this function is a user-defined constructor or destructor, mark down the type as "managed"
+	if ( ! dwt->linkage.is_overrideable && CodeGen::isCtorDtor( dwt->name ) ) {
+		auto & params = GenPoly::getFunctionType( dwt->get_type())->params;
+		assert( ! params.empty() );
+		// Type * type = InitTweak::getPointerBase( params.front() );
+		// assert( type );
+		managedTypes.insert( Mangle::mangle( params.front(), {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
+	}
+}
+
+void ManagedTypes::handleStruct( const ast::StructDecl * aggregateDecl ) {
+	// don't construct members, but need to take note if there is a managed member,
+	// because that means that this type is also managed
+	for ( auto & member : aggregateDecl->members ) {
+		if ( auto field = member.as<ast::ObjectDecl>() ) {
+			if ( isManaged( field ) ) {
+				// generic parameters should not play a role in determining whether a generic type is constructed - construct all generic types, so that
+				// polymorphic constructors make generic types managed types
+				ast::StructInstType inst( aggregateDecl );
+				managedTypes.insert( Mangle::mangle( &inst, {Mangle::NoOverrideable | Mangle::NoGenericParams | Mangle::Type} ) );
+				break;
+			}
+		}
+	}
+}
+
+void ManagedTypes::beginScope() { managedTypes.beginScope(); }
+void ManagedTypes::endScope() { managedTypes.endScope(); }
+
+const ast::Stmt * genCtorDtor( const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg ) {
+	assertf(objDecl, "genCtorDtor passed null objDecl");
+	InitExpander srcParam(arg);
+	return SymTab::genImplicitCall(srcParam, new ast::VariableExpr(loc, objDecl), loc, fname, objDecl);
+}
+
+ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) {
+	// call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each
+	// constructable object
+	InitExpander srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
+	ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
+
+	ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
+		srcParam, dstParam, loc, "?{}", objDecl );
+	ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
+		nullParam, dstParam, loc, "^?{}", objDecl,
+		SymTab::LoopBackward );
+
+	// check that either both ctor and dtor are present, or neither
+	assert( (bool)ctor == (bool)dtor );
+
+	if ( ctor ) {
+		// need to remember init expression, in case no ctors exist. If ctor does exist, want to
+		// use ctor expression instead of init.
+		ctor.strict_as< ast::ImplicitCtorDtorStmt >();
+		dtor.strict_as< ast::ImplicitCtorDtorStmt >();
+
+		return new ast::ConstructorInit{ loc, ctor, dtor, objDecl->init };
+	}
+
+	return nullptr;
+}
+
+} // namespace InitTweak
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/InitTweak/GenInit.h
===================================================================
--- src/InitTweak/GenInit.h	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,60 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// GenInit.h -- Generate initializers, and other stuff.
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri Mar 18 14:22:00 2022
-// Update Count     : 7
-//
-
-#pragma once
-
-#include <list>                // for list
-#include <string>              // for string
-
-#include "AST/Fwd.hpp"
-#include "Common/CodeLocation.h"
-#include "GenPoly/ScopedSet.h" // for ScopedSet
-
-namespace InitTweak {
-
-/// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
-void genInit( ast::TranslationUnit & translationUnit );
-
-/// Converts return statements into copy constructor calls on the hidden return variable.
-/// This pass must happen before auto-gen.
-void fixReturnStatements( ast::TranslationUnit & translationUnit );
-
-/// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
-const ast::Stmt * genCtorDtor( const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr );
-
-/// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
-ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
-
-class ManagedTypes final {
-public:
-	bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed
-	bool isManaged( const ast::Type * type ) const; // determine if type is managed
-
-	void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor
-	void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed
-
-	void beginScope();
-	void endScope();
-private:
-	GenPoly::ScopedSet< std::string > managedTypes;
-};
-
-} // namespace
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/InitTweak/GenInit.hpp
===================================================================
--- src/InitTweak/GenInit.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/InitTweak/GenInit.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,60 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// GenInit.hpp -- Generate initializers, and other stuff.
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Mar 18 14:22:00 2022
+// Update Count     : 7
+//
+
+#pragma once
+
+#include <list>                // for list
+#include <string>              // for string
+
+#include "AST/Fwd.hpp"
+#include "Common/CodeLocation.hpp"
+#include "GenPoly/ScopedSet.hpp"   // for ScopedSet
+
+namespace InitTweak {
+
+/// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
+void genInit( ast::TranslationUnit & translationUnit );
+
+/// Converts return statements into copy constructor calls on the hidden return variable.
+/// This pass must happen before auto-gen.
+void fixReturnStatements( ast::TranslationUnit & translationUnit );
+
+/// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
+const ast::Stmt * genCtorDtor( const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr );
+
+/// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
+ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl );
+
+class ManagedTypes final {
+public:
+	bool isManaged( const ast::ObjectDecl * objDecl ) const ; // determine if object is managed
+	bool isManaged( const ast::Type * type ) const; // determine if type is managed
+
+	void handleDWT( const ast::DeclWithType * dwt ); // add type to managed if ctor/dtor
+	void handleStruct( const ast::StructDecl * aggregateDecl ); // add type to managed if child is managed
+
+	void beginScope();
+	void endScope();
+private:
+	GenPoly::ScopedSet< std::string > managedTypes;
+};
+
+} // namespace
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,475 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// InitTweak.cc --
-//
-// Author           : Rob Schluntz
-// Created On       : Fri May 13 11:26:36 2016
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Sep 22  9:50:00 2022
-// Update Count     : 21
-//
-
-#include "InitTweak.h"
-
-#include <algorithm>               // for find, all_of
-#include <cassert>                 // for assertf, assert, strict_dynamic_cast
-#include <iostream>                // for ostream, cerr, endl
-#include <iterator>                // for back_insert_iterator, back_inserter
-#include <memory>                  // for __shared_ptr
-#include <vector>
-
-#include "AST/Expr.hpp"
-#include "AST/Init.hpp"
-#include "AST/Inspect.hpp"
-#include "AST/Node.hpp"
-#include "AST/Pass.hpp"
-#include "AST/Stmt.hpp"
-#include "AST/Type.hpp"
-#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/ToString.hpp"     // for toCString
-#include "Common/UniqueName.h"     // for UniqueName
-#include "GenPoly/GenPoly.h"       // for getFunctionType
-#include "ResolvExpr/Unify.h"      // for typesCompatibleIgnoreQualifiers
-#include "Tuples/Tuples.h"         // for Tuples::isTtype
-
-namespace InitTweak {
-
-// Forward declared, because it is used as a parent type.
-class InitExpander::ExpanderImpl {
-public:
-	virtual ~ExpanderImpl() = default;
-	virtual std::vector< ast::ptr< ast::Expr > > next( IndexList & indices ) = 0;
-	virtual ast::ptr< ast::Stmt > buildListInit(
-		ast::UntypedExpr * callExpr, IndexList & indices ) = 0;
-};
-
-namespace {
-	struct HasDesignations : public ast::WithShortCircuiting {
-		bool result = false;
-
-		void previsit( const ast::Node * ) {
-			// Short circuit if we already know there are designations.
-			if ( result ) visit_children = false;
-		}
-
-		void previsit( const ast::Designation * des ) {
-			// Short circuit if we already know there are designations.
-			if ( result ) visit_children = false;
-			else if ( !des->designators.empty() ) {
-				result = true;
-				visit_children = false;
-			}
-		}
-	};
-
-	struct InitDepthChecker {
-		bool result = true;
-		const ast::Type * type;
-		int curDepth = 0, maxDepth = 0;
-		InitDepthChecker( const ast::Type * type ) : type( type ) {
-			const ast::Type * t = type;
-			while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
-				maxDepth++;
-				t = at->base;
-			}
-			maxDepth++;
-		}
-		void previsit( ast::ListInit const * ) {
-			curDepth++;
-			if ( curDepth > maxDepth ) result = false;
-		}
-		void postvisit( ast::ListInit const * ) {
-			curDepth--;
-		}
-	};
-
-	struct InitFlattener : public ast::WithShortCircuiting {
-		std::vector< ast::ptr< ast::Expr > > argList;
-
-		void previsit( const ast::SingleInit * singleInit ) {
-			visit_children = false;
-			argList.emplace_back( singleInit->value );
-		}
-	};
-
-	template< typename Out >
-	void buildCallExpr(
-		ast::UntypedExpr * callExpr, const ast::Expr * index, const ast::Expr * dimension,
-		const ast::Init * init, Out & out
-	) {
-		const CodeLocation & loc = init->location;
-
-		auto cond = new ast::UntypedExpr{
-			loc, new ast::NameExpr{ loc, "?<?" }, { index, dimension } };
-
-		std::vector< ast::ptr< ast::Expr > > args = makeInitList( init );
-		splice( callExpr->args, args );
-
-		out.emplace_back( new ast::IfStmt{ loc, cond, new ast::ExprStmt{ loc, callExpr } } );
-
-		out.emplace_back( new ast::ExprStmt{
-			loc, new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, "++?" }, { index } } } );
-	}
-
-	template< typename Out >
-	void build(
-		ast::UntypedExpr * callExpr, const InitExpander::IndexList & indices,
-		const ast::Init * init, Out & out
-	) {
-		if ( indices.empty() ) return;
-
-		unsigned idx = 0;
-
-		const ast::Expr * index = indices[idx++];
-		assert( idx != indices.size() );
-		const ast::Expr * dimension = indices[idx++];
-
-		if ( idx == indices.size() ) {
-			if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) {
-				for ( const ast::Init * init : *listInit ) {
-					buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
-				}
-			} else {
-				buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
-			}
-		} else {
-			const CodeLocation & loc = init->location;
-
-			unsigned long cond = 0;
-			auto listInit = dynamic_cast< const ast::ListInit * >( init );
-			if ( ! listInit ) { SemanticError( loc, "unbalanced list initializers" ); }
-
-			static UniqueName targetLabel( "L__autogen__" );
-			ast::Label switchLabel{
-				loc, targetLabel.newName(), { new ast::Attribute{ "unused" } } };
-
-			std::vector< ast::ptr< ast::CaseClause > > branches;
-			for ( const ast::Init * init : *listInit ) {
-				auto condition = ast::ConstantExpr::from_ulong( loc, cond );
-				++cond;
-
-				std::vector< ast::ptr< ast::Stmt > > stmts;
-				build( callExpr, indices, init, stmts );
-				stmts.emplace_back(
-					new ast::BranchStmt{ loc, ast::BranchStmt::Break, switchLabel } );
-				branches.emplace_back( new ast::CaseClause{ loc, condition, std::move( stmts ) } );
-			}
-			out.emplace_back( new ast::SwitchStmt{ loc, index, std::move( branches ) } );
-			out.emplace_back( new ast::NullStmt{ loc, { switchLabel } } );
-		}
-	}
-
-	class InitImpl final : public InitExpander::ExpanderImpl {
-		ast::ptr< ast::Init > init;
-	public:
-		InitImpl( const ast::Init * i ) : init( i ) {}
-
-		std::vector< ast::ptr< ast::Expr > > next( InitExpander::IndexList & ) override {
-			return makeInitList( init );
-		}
-
-		ast::ptr< ast::Stmt > buildListInit(
-			ast::UntypedExpr * callExpr, InitExpander::IndexList & indices
-		) override {
-			// If array came with an initializer list, initialize each element. We may have more
-			// initializers than elements of the array; need to check at each index that we have
-			// not exceeded size. We may have fewer initializers than elements in the array; need
-			// to default-construct remaining elements. To accomplish this, generate switch
-			// statement consuming all of expander's elements
-
-			if ( ! init ) return {};
-
-			std::list< ast::ptr< ast::Stmt > > stmts;
-			build( callExpr, indices, init, stmts );
-			if ( stmts.empty() ) {
-				return {};
-			} else if ( 1 == stmts.size() ) {
-				return std::move( stmts.front() );
-			} else {
-				auto block = new ast::CompoundStmt{ init->location, std::move( stmts ) };
-				init = nullptr;  // consumed in creating the list init
-				return block;
-			}
-		}
-	};
-
-	class ExprImpl final : public InitExpander::ExpanderImpl {
-		ast::ptr< ast::Expr > arg;
-	public:
-		ExprImpl( const ast::Expr * a ) : arg( a ) {}
-
-		std::vector< ast::ptr< ast::Expr > > next(
-			InitExpander::IndexList & indices
-		) override {
-			if ( !arg ) return {};
-
-			const CodeLocation & loc = arg->location;
-			const ast::Expr * expr = arg;
-			for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) {
-				// Go through indices and layer on subscript exprs ?[?].
-				++it;
-				expr = new ast::UntypedExpr{
-					loc, new ast::NameExpr{ loc, "?[?]" }, { expr, *it } };
-			}
-			return { expr };
-		}
-
-		ast::ptr< ast::Stmt > buildListInit(
-			ast::UntypedExpr *, InitExpander::IndexList &
-		) override {
-			return {};
-		}
-	};
-
-	struct CallFinder final {
-		std::vector< const ast::Expr * > matches;
-		const std::vector< std::string > names;
-
-		CallFinder( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
-
-		void handleCallExpr( const ast::Expr * expr ) {
-			std::string fname = getFunctionName( expr );
-			if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
-				matches.emplace_back( expr );
-			}
-		}
-
-		void postvisit( const ast::ApplicationExpr * expr ) { handleCallExpr( expr ); }
-		void postvisit( const ast::UntypedExpr *     expr ) { handleCallExpr( expr ); }
-	};
-
-	template <typename Predicate>
-	bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
-		std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
-		return std::all_of( callExprs.begin(), callExprs.end(), pred );
-	}
-
-	struct ConstExprChecker : public ast::WithShortCircuiting {
-		// Most expressions are not const-expr.
-		void previsit( const ast::Expr * ) { result = false; visit_children = false; }
-
-		void previsit( const ast::AddressExpr *addressExpr ) {
-			visit_children = false;
-			const ast::Expr * arg = addressExpr->arg;
-
-			// Address of a variable or member expression is const-expr.
-			if ( !dynamic_cast< const ast::NameExpr * >( arg )
-				&& !dynamic_cast< const ast::VariableExpr * >( arg )
-				&& !dynamic_cast< const ast::MemberExpr * >( arg )
-				&& !dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;
-		}
-
-		// These expressions may be const expr, depending on their children.
-		void previsit( const ast::SizeofExpr * ) {}
-		void previsit( const ast::AlignofExpr * ) {}
-		void previsit( const ast::UntypedOffsetofExpr * ) {}
-		void previsit( const ast::OffsetofExpr * ) {}
-		void previsit( const ast::OffsetPackExpr * ) {}
-		void previsit( const ast::CommaExpr * ) {}
-		void previsit( const ast::LogicalExpr * ) {}
-		void previsit( const ast::ConditionalExpr * ) {}
-		void previsit( const ast::CastExpr * ) {}
-		void previsit( const ast::ConstantExpr * ) {}
-
-		void previsit( const ast::VariableExpr * varExpr ) {
-			visit_children = false;
-
-			if ( auto inst = varExpr->result.as<ast::EnumInstType>() ) {
-				long long int value;
-				if ( inst->base->valueOf( varExpr->var, value ) ) {
-					// enumerators are const expr
-					return;
-				}
-			}
-			result = false;
-		}
-
-		bool result = true;
-	};
-} // namespace
-
-bool isAssignment( const ast::FunctionDecl * decl ) {
-	return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
-}
-
-bool isDestructor( const ast::FunctionDecl * decl ) {
-	return CodeGen::isDestructor( decl->name );
-}
-
-bool isDefaultConstructor( const ast::FunctionDecl * decl ) {
-	return CodeGen::isConstructor( decl->name ) && 1 == decl->params.size();
-}
-
-bool isCopyConstructor( const ast::FunctionDecl * decl ) {
-	return CodeGen::isConstructor( decl->name ) && 2 == decl->params.size();
-}
-
-bool isCopyFunction( const ast::FunctionDecl * decl ) {
-	const ast::FunctionType * ftype = decl->type;
-	if ( ftype->params.size() != 2 ) return false;
-
-	const ast::Type * t1 = ast::getPointerBase( ftype->params.front() );
-	if ( ! t1 ) return false;
-	const ast::Type * t2 = ftype->params.back();
-
-	return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
-}
-
-const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
-	assertf( ftype, "getTypeofThis: nullptr ftype" );
-	const std::vector<ast::ptr<ast::Type>> & params = ftype->params;
-	assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s",
-			toCString( ftype ) );
-	const ast::ReferenceType * refType =
-		params.front().strict_as<ast::ReferenceType>();
-	return refType->base;
-}
-
-const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
-	assertf( func, "getParamThis: nullptr ftype" );
-	auto & params = func->params;
-	assertf( !params.empty(), "getParamThis: ftype with 0 parameters: %s", toCString( func ));
-	return params.front().strict_as<ast::ObjectDecl>();
-}
-
-// looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards
-// following passes may accidentally resolve this expression if returned as untyped...
-ast::Expr * createBitwiseAssignment(const ast::Expr * dst, const ast::Expr * src) {
-	static ast::ptr<ast::FunctionDecl> assign = nullptr;
-	if (!assign) {
-		auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true);
-		assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td}, {},
-		{ new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
-		  new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))},
-		{ new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic);
-	}
-	if (dst->result.as<ast::ReferenceType>()) {
-		for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
-			dst = new ast::AddressExpr(dst);
-		}
-	} else {
-		dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
-	}
-	if (src->result.as<ast::ReferenceType>()) {
-		for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
-			src = new ast::AddressExpr(src);
-		}
-	}
-	auto var = ast::VariableExpr::functionPointer(dst->location, assign);
-	auto app = new ast::ApplicationExpr(dst->location, var, {dst, src});
-	// Skip the resolver, just set the result to the correct type.
-	app->result = ast::deepCopy( src->result );
-	return app;
-}
-
-std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
-	ast::Pass< InitFlattener > flattener;
-	maybe_accept( init, flattener );
-	return std::move( flattener.core.argList );
-}
-
-bool tryConstruct( const ast::DeclWithType * dwt ) {
-	auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );
-	if ( !objDecl ) return false;
-	return (objDecl->init == nullptr ||
-			( objDecl->init != nullptr && objDecl->init->maybeConstructed ))
-		&& !objDecl->storage.is_extern
-		&& isConstructable( objDecl->type );
-}
-
-bool isConstructable( const ast::Type * type ) {
-	return !dynamic_cast< const ast::VarArgsType * >( type ) && !dynamic_cast< const ast::ReferenceType * >( type )
-		&& !dynamic_cast< const ast::FunctionType * >( type ) && !Tuples::isTtype( type );
-}
-
-bool isDesignated( const ast::Init * init ) {
-	return ( init ) ? ast::Pass<HasDesignations>::read( init ) : false;
-}
-
-bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
-	return ( objDecl->init ) ? ast::Pass<InitDepthChecker>::read(
-		objDecl->init.get(), objDecl->type.get() ) : true;
-}
-
-bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) {
-	return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){
-		if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
-			const ast::FunctionType * funcType =
-				GenPoly::getFunctionType( appExpr->func->result );
-			assert( funcType );
-			return funcType->params.size() == 1;
-		}
-		return false;
-	});
-}
-
-std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
-	ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
-	maybe_accept( stmt, finder );
-	return std::move( finder.core.matches );
-}
-
-bool isConstExpr( const ast::Expr * expr ) {
-	return ( expr ) ? ast::Pass<ConstExprChecker>::read( expr ) : true;
-}
-
-bool isConstExpr( const ast::Init * init ) {
-	// for all intents and purposes, no initializer means const expr
-	return ( init ) ? ast::Pass<ConstExprChecker>::read( init ) : true;
-}
-
-#if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
-	#define ASM_COMMENT "#"
-#else // defined( __ARM_ARCH )
-	#define ASM_COMMENT "//"
-#endif
-static const char * const data_section =  ".data" ASM_COMMENT;
-static const char * const tlsd_section = ".tdata" ASM_COMMENT;
-
-void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
-	const bool is_tls = objDecl->storage.is_threadlocal_any();
-	const char * section = is_tls ? tlsd_section : data_section;
-	objDecl->attributes.push_back(new ast::Attribute("section", {
-		ast::ConstantExpr::from_string(objDecl->location, section)
-	}));
-}
-
-InitExpander::InitExpander( const ast::Init * init )
-: expander( new InitImpl{ init } ), crnt(), indices() {}
-
-InitExpander::InitExpander( const ast::Expr * expr )
-: expander( new ExprImpl{ expr } ), crnt(), indices() {}
-
-std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }
-
-InitExpander & InitExpander::operator++ () {
-	crnt = expander->next( indices );
-	return *this;
-}
-
-/// builds statement which has the same semantics as a C-style list initializer (for array
-/// initializers) using callExpr as the base expression to perform initialization
-ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {
-	return expander->buildListInit( callExpr, indices );
-}
-
-void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
-	indices.emplace_back( index );
-	indices.emplace_back( dimension );
-}
-
-void InitExpander::clearArrayIndices() { indices.clear(); }
-
-bool InitExpander::addReference() {
-	for ( ast::ptr< ast::Expr > & expr : crnt ) {
-		expr = new ast::AddressExpr{ expr };
-	}
-	return !crnt.empty();
-}
-
-} // namespace InitTweak
Index: src/InitTweak/InitTweak.cpp
===================================================================
--- src/InitTweak/InitTweak.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/InitTweak/InitTweak.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,475 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// InitTweak.cpp --
+//
+// Author           : Rob Schluntz
+// Created On       : Fri May 13 11:26:36 2016
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Sep 22  9:50:00 2022
+// Update Count     : 21
+//
+
+#include "InitTweak.hpp"
+
+#include <algorithm>                  // for find, all_of
+#include <cassert>                    // for assertf, assert, strict_dynamic_...
+#include <iostream>                   // for ostream, cerr, endl
+#include <iterator>                   // for back_insert_iterator, back_inser...
+#include <memory>                     // for __shared_ptr
+#include <vector>
+
+#include "AST/Expr.hpp"
+#include "AST/Init.hpp"
+#include "AST/Inspect.hpp"
+#include "AST/Node.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Stmt.hpp"
+#include "AST/Type.hpp"
+#include "CodeGen/OperatorTable.hpp"  // for isConstructor, isDestructor, isC...
+#include "Common/SemanticError.hpp"   // for SemanticError
+#include "Common/ToString.hpp"        // for toCString
+#include "Common/UniqueName.hpp"      // for UniqueName
+#include "GenPoly/GenPoly.hpp"        // for getFunctionType
+#include "ResolvExpr/Unify.hpp"       // for typesCompatibleIgnoreQualifiers
+#include "Tuples/Tuples.hpp"          // for Tuples::isTtype
+
+namespace InitTweak {
+
+// Forward declared, because it is used as a parent type.
+class InitExpander::ExpanderImpl {
+public:
+	virtual ~ExpanderImpl() = default;
+	virtual std::vector< ast::ptr< ast::Expr > > next( IndexList & indices ) = 0;
+	virtual ast::ptr< ast::Stmt > buildListInit(
+		ast::UntypedExpr * callExpr, IndexList & indices ) = 0;
+};
+
+namespace {
+	struct HasDesignations : public ast::WithShortCircuiting {
+		bool result = false;
+
+		void previsit( const ast::Node * ) {
+			// Short circuit if we already know there are designations.
+			if ( result ) visit_children = false;
+		}
+
+		void previsit( const ast::Designation * des ) {
+			// Short circuit if we already know there are designations.
+			if ( result ) visit_children = false;
+			else if ( !des->designators.empty() ) {
+				result = true;
+				visit_children = false;
+			}
+		}
+	};
+
+	struct InitDepthChecker {
+		bool result = true;
+		const ast::Type * type;
+		int curDepth = 0, maxDepth = 0;
+		InitDepthChecker( const ast::Type * type ) : type( type ) {
+			const ast::Type * t = type;
+			while ( auto at = dynamic_cast< const ast::ArrayType * >( t ) ) {
+				maxDepth++;
+				t = at->base;
+			}
+			maxDepth++;
+		}
+		void previsit( ast::ListInit const * ) {
+			curDepth++;
+			if ( curDepth > maxDepth ) result = false;
+		}
+		void postvisit( ast::ListInit const * ) {
+			curDepth--;
+		}
+	};
+
+	struct InitFlattener : public ast::WithShortCircuiting {
+		std::vector< ast::ptr< ast::Expr > > argList;
+
+		void previsit( const ast::SingleInit * singleInit ) {
+			visit_children = false;
+			argList.emplace_back( singleInit->value );
+		}
+	};
+
+	template< typename Out >
+	void buildCallExpr(
+		ast::UntypedExpr * callExpr, const ast::Expr * index, const ast::Expr * dimension,
+		const ast::Init * init, Out & out
+	) {
+		const CodeLocation & loc = init->location;
+
+		auto cond = new ast::UntypedExpr{
+			loc, new ast::NameExpr{ loc, "?<?" }, { index, dimension } };
+
+		std::vector< ast::ptr< ast::Expr > > args = makeInitList( init );
+		splice( callExpr->args, args );
+
+		out.emplace_back( new ast::IfStmt{ loc, cond, new ast::ExprStmt{ loc, callExpr } } );
+
+		out.emplace_back( new ast::ExprStmt{
+			loc, new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, "++?" }, { index } } } );
+	}
+
+	template< typename Out >
+	void build(
+		ast::UntypedExpr * callExpr, const InitExpander::IndexList & indices,
+		const ast::Init * init, Out & out
+	) {
+		if ( indices.empty() ) return;
+
+		unsigned idx = 0;
+
+		const ast::Expr * index = indices[idx++];
+		assert( idx != indices.size() );
+		const ast::Expr * dimension = indices[idx++];
+
+		if ( idx == indices.size() ) {
+			if ( auto listInit = dynamic_cast< const ast::ListInit * >( init ) ) {
+				for ( const ast::Init * init : *listInit ) {
+					buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
+				}
+			} else {
+				buildCallExpr( shallowCopy(callExpr), index, dimension, init, out );
+			}
+		} else {
+			const CodeLocation & loc = init->location;
+
+			unsigned long cond = 0;
+			auto listInit = dynamic_cast< const ast::ListInit * >( init );
+			if ( ! listInit ) { SemanticError( loc, "unbalanced list initializers" ); }
+
+			static UniqueName targetLabel( "L__autogen__" );
+			ast::Label switchLabel{
+				loc, targetLabel.newName(), { new ast::Attribute{ "unused" } } };
+
+			std::vector< ast::ptr< ast::CaseClause > > branches;
+			for ( const ast::Init * init : *listInit ) {
+				auto condition = ast::ConstantExpr::from_ulong( loc, cond );
+				++cond;
+
+				std::vector< ast::ptr< ast::Stmt > > stmts;
+				build( callExpr, indices, init, stmts );
+				stmts.emplace_back(
+					new ast::BranchStmt{ loc, ast::BranchStmt::Break, switchLabel } );
+				branches.emplace_back( new ast::CaseClause{ loc, condition, std::move( stmts ) } );
+			}
+			out.emplace_back( new ast::SwitchStmt{ loc, index, std::move( branches ) } );
+			out.emplace_back( new ast::NullStmt{ loc, { switchLabel } } );
+		}
+	}
+
+	class InitImpl final : public InitExpander::ExpanderImpl {
+		ast::ptr< ast::Init > init;
+	public:
+		InitImpl( const ast::Init * i ) : init( i ) {}
+
+		std::vector< ast::ptr< ast::Expr > > next( InitExpander::IndexList & ) override {
+			return makeInitList( init );
+		}
+
+		ast::ptr< ast::Stmt > buildListInit(
+			ast::UntypedExpr * callExpr, InitExpander::IndexList & indices
+		) override {
+			// If array came with an initializer list, initialize each element. We may have more
+			// initializers than elements of the array; need to check at each index that we have
+			// not exceeded size. We may have fewer initializers than elements in the array; need
+			// to default-construct remaining elements. To accomplish this, generate switch
+			// statement consuming all of expander's elements
+
+			if ( ! init ) return {};
+
+			std::list< ast::ptr< ast::Stmt > > stmts;
+			build( callExpr, indices, init, stmts );
+			if ( stmts.empty() ) {
+				return {};
+			} else if ( 1 == stmts.size() ) {
+				return std::move( stmts.front() );
+			} else {
+				auto block = new ast::CompoundStmt{ init->location, std::move( stmts ) };
+				init = nullptr;  // consumed in creating the list init
+				return block;
+			}
+		}
+	};
+
+	class ExprImpl final : public InitExpander::ExpanderImpl {
+		ast::ptr< ast::Expr > arg;
+	public:
+		ExprImpl( const ast::Expr * a ) : arg( a ) {}
+
+		std::vector< ast::ptr< ast::Expr > > next(
+			InitExpander::IndexList & indices
+		) override {
+			if ( !arg ) return {};
+
+			const CodeLocation & loc = arg->location;
+			const ast::Expr * expr = arg;
+			for ( auto it = indices.rbegin(); it != indices.rend(); ++it ) {
+				// Go through indices and layer on subscript exprs ?[?].
+				++it;
+				expr = new ast::UntypedExpr{
+					loc, new ast::NameExpr{ loc, "?[?]" }, { expr, *it } };
+			}
+			return { expr };
+		}
+
+		ast::ptr< ast::Stmt > buildListInit(
+			ast::UntypedExpr *, InitExpander::IndexList &
+		) override {
+			return {};
+		}
+	};
+
+	struct CallFinder final {
+		std::vector< const ast::Expr * > matches;
+		const std::vector< std::string > names;
+
+		CallFinder( std::vector< std::string > && ns ) : matches(), names( std::move(ns) ) {}
+
+		void handleCallExpr( const ast::Expr * expr ) {
+			std::string fname = getFunctionName( expr );
+			if ( std::find( names.begin(), names.end(), fname ) != names.end() ) {
+				matches.emplace_back( expr );
+			}
+		}
+
+		void postvisit( const ast::ApplicationExpr * expr ) { handleCallExpr( expr ); }
+		void postvisit( const ast::UntypedExpr *     expr ) { handleCallExpr( expr ); }
+	};
+
+	template <typename Predicate>
+	bool allofCtorDtor( const ast::Stmt * stmt, const Predicate & pred ) {
+		std::vector< const ast::Expr * > callExprs = collectCtorDtorCalls( stmt );
+		return std::all_of( callExprs.begin(), callExprs.end(), pred );
+	}
+
+	struct ConstExprChecker : public ast::WithShortCircuiting {
+		// Most expressions are not const-expr.
+		void previsit( const ast::Expr * ) { result = false; visit_children = false; }
+
+		void previsit( const ast::AddressExpr *addressExpr ) {
+			visit_children = false;
+			const ast::Expr * arg = addressExpr->arg;
+
+			// Address of a variable or member expression is const-expr.
+			if ( !dynamic_cast< const ast::NameExpr * >( arg )
+				&& !dynamic_cast< const ast::VariableExpr * >( arg )
+				&& !dynamic_cast< const ast::MemberExpr * >( arg )
+				&& !dynamic_cast< const ast::UntypedMemberExpr * >( arg ) ) result = false;
+		}
+
+		// These expressions may be const expr, depending on their children.
+		void previsit( const ast::SizeofExpr * ) {}
+		void previsit( const ast::AlignofExpr * ) {}
+		void previsit( const ast::UntypedOffsetofExpr * ) {}
+		void previsit( const ast::OffsetofExpr * ) {}
+		void previsit( const ast::OffsetPackExpr * ) {}
+		void previsit( const ast::CommaExpr * ) {}
+		void previsit( const ast::LogicalExpr * ) {}
+		void previsit( const ast::ConditionalExpr * ) {}
+		void previsit( const ast::CastExpr * ) {}
+		void previsit( const ast::ConstantExpr * ) {}
+
+		void previsit( const ast::VariableExpr * varExpr ) {
+			visit_children = false;
+
+			if ( auto inst = varExpr->result.as<ast::EnumInstType>() ) {
+				long long int value;
+				if ( inst->base->valueOf( varExpr->var, value ) ) {
+					// enumerators are const expr
+					return;
+				}
+			}
+			result = false;
+		}
+
+		bool result = true;
+	};
+} // namespace
+
+bool isAssignment( const ast::FunctionDecl * decl ) {
+	return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
+}
+
+bool isDestructor( const ast::FunctionDecl * decl ) {
+	return CodeGen::isDestructor( decl->name );
+}
+
+bool isDefaultConstructor( const ast::FunctionDecl * decl ) {
+	return CodeGen::isConstructor( decl->name ) && 1 == decl->params.size();
+}
+
+bool isCopyConstructor( const ast::FunctionDecl * decl ) {
+	return CodeGen::isConstructor( decl->name ) && 2 == decl->params.size();
+}
+
+bool isCopyFunction( const ast::FunctionDecl * decl ) {
+	const ast::FunctionType * ftype = decl->type;
+	if ( ftype->params.size() != 2 ) return false;
+
+	const ast::Type * t1 = ast::getPointerBase( ftype->params.front() );
+	if ( ! t1 ) return false;
+	const ast::Type * t2 = ftype->params.back();
+
+	return ResolvExpr::typesCompatibleIgnoreQualifiers( t1, t2 );
+}
+
+const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
+	assertf( ftype, "getTypeofThis: nullptr ftype" );
+	const std::vector<ast::ptr<ast::Type>> & params = ftype->params;
+	assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s",
+			toCString( ftype ) );
+	const ast::ReferenceType * refType =
+		params.front().strict_as<ast::ReferenceType>();
+	return refType->base;
+}
+
+const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func) {
+	assertf( func, "getParamThis: nullptr ftype" );
+	auto & params = func->params;
+	assertf( !params.empty(), "getParamThis: ftype with 0 parameters: %s", toCString( func ));
+	return params.front().strict_as<ast::ObjectDecl>();
+}
+
+// looks like some other such codegen uses UntypedExpr and does not create fake function. should revisit afterwards
+// following passes may accidentally resolve this expression if returned as untyped...
+ast::Expr * createBitwiseAssignment(const ast::Expr * dst, const ast::Expr * src) {
+	static ast::ptr<ast::FunctionDecl> assign = nullptr;
+	if (!assign) {
+		auto td = new ast::TypeDecl(CodeLocation(), "T", {}, nullptr, ast::TypeDecl::Dtype, true);
+		assign = new ast::FunctionDecl(CodeLocation(), "?=?", {td}, {},
+		{ new ast::ObjectDecl(CodeLocation(), "_dst", new ast::ReferenceType(new ast::TypeInstType("T", td))),
+		  new ast::ObjectDecl(CodeLocation(), "_src", new ast::TypeInstType("T", td))},
+		{ new ast::ObjectDecl(CodeLocation(), "_ret", new ast::TypeInstType("T", td))}, nullptr, {}, ast::Linkage::Intrinsic);
+	}
+	if (dst->result.as<ast::ReferenceType>()) {
+		for (int depth = dst->result->referenceDepth(); depth > 0; depth--) {
+			dst = new ast::AddressExpr(dst);
+		}
+	} else {
+		dst = new ast::CastExpr(dst, new ast::ReferenceType(dst->result, {}));
+	}
+	if (src->result.as<ast::ReferenceType>()) {
+		for (int depth = src->result->referenceDepth(); depth > 0; depth--) {
+			src = new ast::AddressExpr(src);
+		}
+	}
+	auto var = ast::VariableExpr::functionPointer(dst->location, assign);
+	auto app = new ast::ApplicationExpr(dst->location, var, {dst, src});
+	// Skip the resolver, just set the result to the correct type.
+	app->result = ast::deepCopy( src->result );
+	return app;
+}
+
+std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init ) {
+	ast::Pass< InitFlattener > flattener;
+	maybe_accept( init, flattener );
+	return std::move( flattener.core.argList );
+}
+
+bool tryConstruct( const ast::DeclWithType * dwt ) {
+	auto objDecl = dynamic_cast< const ast::ObjectDecl * >( dwt );
+	if ( !objDecl ) return false;
+	return (objDecl->init == nullptr ||
+			( objDecl->init != nullptr && objDecl->init->maybeConstructed ))
+		&& !objDecl->storage.is_extern
+		&& isConstructable( objDecl->type );
+}
+
+bool isConstructable( const ast::Type * type ) {
+	return !dynamic_cast< const ast::VarArgsType * >( type ) && !dynamic_cast< const ast::ReferenceType * >( type )
+		&& !dynamic_cast< const ast::FunctionType * >( type ) && !Tuples::isTtype( type );
+}
+
+bool isDesignated( const ast::Init * init ) {
+	return ( init ) ? ast::Pass<HasDesignations>::read( init ) : false;
+}
+
+bool checkInitDepth( const ast::ObjectDecl * objDecl ) {
+	return ( objDecl->init ) ? ast::Pass<InitDepthChecker>::read(
+		objDecl->init.get(), objDecl->type.get() ) : true;
+}
+
+bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt ) {
+	return allofCtorDtor( stmt, []( const ast::Expr * callExpr ){
+		if ( const ast::ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
+			const ast::FunctionType * funcType =
+				GenPoly::getFunctionType( appExpr->func->result );
+			assert( funcType );
+			return funcType->params.size() == 1;
+		}
+		return false;
+	});
+}
+
+std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt ) {
+	ast::Pass< CallFinder > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
+	maybe_accept( stmt, finder );
+	return std::move( finder.core.matches );
+}
+
+bool isConstExpr( const ast::Expr * expr ) {
+	return ( expr ) ? ast::Pass<ConstExprChecker>::read( expr ) : true;
+}
+
+bool isConstExpr( const ast::Init * init ) {
+	// for all intents and purposes, no initializer means const expr
+	return ( init ) ? ast::Pass<ConstExprChecker>::read( init ) : true;
+}
+
+#if defined( __x86_64 ) || defined( __i386 ) // assembler comment to prevent assembler warning message
+	#define ASM_COMMENT "#"
+#else // defined( __ARM_ARCH )
+	#define ASM_COMMENT "//"
+#endif
+static const char * const data_section =  ".data" ASM_COMMENT;
+static const char * const tlsd_section = ".tdata" ASM_COMMENT;
+
+void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
+	const bool is_tls = objDecl->storage.is_threadlocal_any();
+	const char * section = is_tls ? tlsd_section : data_section;
+	objDecl->attributes.push_back(new ast::Attribute("section", {
+		ast::ConstantExpr::from_string(objDecl->location, section)
+	}));
+}
+
+InitExpander::InitExpander( const ast::Init * init )
+: expander( new InitImpl{ init } ), crnt(), indices() {}
+
+InitExpander::InitExpander( const ast::Expr * expr )
+: expander( new ExprImpl{ expr } ), crnt(), indices() {}
+
+std::vector< ast::ptr< ast::Expr > > InitExpander::operator* () { return crnt; }
+
+InitExpander & InitExpander::operator++ () {
+	crnt = expander->next( indices );
+	return *this;
+}
+
+/// builds statement which has the same semantics as a C-style list initializer (for array
+/// initializers) using callExpr as the base expression to perform initialization
+ast::ptr< ast::Stmt > InitExpander::buildListInit( ast::UntypedExpr * callExpr ) {
+	return expander->buildListInit( callExpr, indices );
+}
+
+void InitExpander::addArrayIndex( const ast::Expr * index, const ast::Expr * dimension ) {
+	indices.emplace_back( index );
+	indices.emplace_back( dimension );
+}
+
+void InitExpander::clearArrayIndices() { indices.clear(); }
+
+bool InitExpander::addReference() {
+	for ( ast::ptr< ast::Expr > & expr : crnt ) {
+		expr = new ast::AddressExpr{ expr };
+	}
+	return !crnt.empty();
+}
+
+} // namespace InitTweak
Index: src/InitTweak/InitTweak.h
===================================================================
--- src/InitTweak/InitTweak.h	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,121 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// InitTweak.h --
-//
-// Author           : Rob Schluntz
-// Created On       : Fri May 13 11:26:36 2016
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Sep 22  9:21:00 2022
-// Update Count     : 9
-//
-
-#pragma once
-
-#include <list>               // for list
-#include <memory>             // for shared_ptr
-#include <string>             // for string, allocator
-#include <vector>
-
-#include "AST/Fwd.hpp"        // for AST nodes
-
-// helper functions for initialization
-namespace InitTweak {
-
-bool isAssignment( const ast::FunctionDecl * decl );
-bool isDestructor( const ast::FunctionDecl * decl );
-bool isDefaultConstructor( const ast::FunctionDecl * decl );
-bool isCopyConstructor( const ast::FunctionDecl * decl );
-bool isCopyFunction( const ast::FunctionDecl * decl );
-
-/// returns the base type of the first parameter to a constructor/destructor/assignment function
-const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
-
-/// returns the first parameter of a constructor/destructor/assignment function
-const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
-
-/// generate a bitwise assignment operation.
-ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
-
-/// transform Initializer into an argument list that can be passed to a call expression
-std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
-
-/// True if the resolver should try to construct dwt
-bool tryConstruct( const ast::DeclWithType * dwt );
-
-/// True if the type can have a user-defined constructor
-bool isConstructable( const ast::Type * t );
-
-/// True if the Initializer contains designations
-bool isDesignated( const ast::Init * init );
-
-/// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
-/// type, where the depth of its type is the number of nested ArrayTypes + 1
-bool checkInitDepth( const ast::ObjectDecl * objDecl );
-
-/// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
-/// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
-/// Currently has assertions that make it less than fully general.
-bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
-
-/// get all Ctor/Dtor call expressions from a Statement
-std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
-
-/// returns true if expr is trivially a compile-time constant
-bool isConstExpr( const ast::Expr * expr );
-bool isConstExpr( const ast::Init * init );
-
-/// Modifies objDecl to have:
-///    __attribute__((section (".data#")))
-/// which makes gcc put the declared variable in the data section,
-/// which is helpful for global constants on newer gcc versions,
-/// so that CFA's generated initialization won't segfault when writing it via a const cast.
-/// The trailing # is an injected assembly comment, to suppress the "a" in
-///    .section .data,"a"
-///    .section .data#,"a"
-/// to avoid assembler warning "ignoring changed section attributes for .data"
-void addDataSectionAttribute( ast::ObjectDecl * objDecl );
-
-class InitExpander final {
-public:
-	using IndexList = std::vector< ast::ptr< ast::Expr > >;
-	class ExpanderImpl;
-
-private:
-	std::shared_ptr< ExpanderImpl > expander;
-	std::vector< ast::ptr< ast::Expr > > crnt;
-	// invariant: list of size 2N (elements come in pairs [index, dimension])
-	IndexList indices;
-
-public:
-	/// Expand by stepping through init to get each list of arguments
-	InitExpander( const ast::Init * init );
-
-	/// Always expand to expression
-	InitExpander( const ast::Expr * expr );
-
-	std::vector< ast::ptr< ast::Expr > > operator* ();
-	InitExpander & operator++ ();
-
-	/// builds statement which has the same semantics as a C-style list initializer (for array
-	/// initializers) using callExpr as the base expression to perform initialization.
-	/// Mutates callExpr
-	ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr );
-
-	void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension );
-
-	void clearArrayIndices();
-
-	bool addReference();
-};
-
-} // namespace InitTweak
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/InitTweak/InitTweak.hpp
===================================================================
--- src/InitTweak/InitTweak.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/InitTweak/InitTweak.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,121 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// InitTweak.h --
+//
+// Author           : Rob Schluntz
+// Created On       : Fri May 13 11:26:36 2016
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Sep 22  9:21:00 2022
+// Update Count     : 9
+//
+
+#pragma once
+
+#include <list>               // for list
+#include <memory>             // for shared_ptr
+#include <string>             // for string, allocator
+#include <vector>
+
+#include "AST/Fwd.hpp"        // for AST nodes
+
+// helper functions for initialization
+namespace InitTweak {
+
+bool isAssignment( const ast::FunctionDecl * decl );
+bool isDestructor( const ast::FunctionDecl * decl );
+bool isDefaultConstructor( const ast::FunctionDecl * decl );
+bool isCopyConstructor( const ast::FunctionDecl * decl );
+bool isCopyFunction( const ast::FunctionDecl * decl );
+
+/// returns the base type of the first parameter to a constructor/destructor/assignment function
+const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
+
+/// returns the first parameter of a constructor/destructor/assignment function
+const ast::ObjectDecl * getParamThis(const ast::FunctionDecl * func);
+
+/// generate a bitwise assignment operation.
+ast::Expr * createBitwiseAssignment( const ast::Expr * dst, const ast::Expr * src);
+
+/// transform Initializer into an argument list that can be passed to a call expression
+std::vector< ast::ptr< ast::Expr > > makeInitList( const ast::Init * init );
+
+/// True if the resolver should try to construct dwt
+bool tryConstruct( const ast::DeclWithType * dwt );
+
+/// True if the type can have a user-defined constructor
+bool isConstructable( const ast::Type * t );
+
+/// True if the Initializer contains designations
+bool isDesignated( const ast::Init * init );
+
+/// True if the ObjectDecl's Initializer nesting level is not deeper than the depth of its
+/// type, where the depth of its type is the number of nested ArrayTypes + 1
+bool checkInitDepth( const ast::ObjectDecl * objDecl );
+
+/// True if stmt is a call statement where the function called is intrinsic and takes one parameter.
+/// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
+/// Currently has assertions that make it less than fully general.
+bool isIntrinsicSingleArgCallStmt( const ast::Stmt * stmt );
+
+/// get all Ctor/Dtor call expressions from a Statement
+std::vector< const ast::Expr * > collectCtorDtorCalls( const ast::Stmt * stmt );
+
+/// returns true if expr is trivially a compile-time constant
+bool isConstExpr( const ast::Expr * expr );
+bool isConstExpr( const ast::Init * init );
+
+/// Modifies objDecl to have:
+///    __attribute__((section (".data#")))
+/// which makes gcc put the declared variable in the data section,
+/// which is helpful for global constants on newer gcc versions,
+/// so that CFA's generated initialization won't segfault when writing it via a const cast.
+/// The trailing # is an injected assembly comment, to suppress the "a" in
+///    .section .data,"a"
+///    .section .data#,"a"
+/// to avoid assembler warning "ignoring changed section attributes for .data"
+void addDataSectionAttribute( ast::ObjectDecl * objDecl );
+
+class InitExpander final {
+public:
+	using IndexList = std::vector< ast::ptr< ast::Expr > >;
+	class ExpanderImpl;
+
+private:
+	std::shared_ptr< ExpanderImpl > expander;
+	std::vector< ast::ptr< ast::Expr > > crnt;
+	// invariant: list of size 2N (elements come in pairs [index, dimension])
+	IndexList indices;
+
+public:
+	/// Expand by stepping through init to get each list of arguments
+	InitExpander( const ast::Init * init );
+
+	/// Always expand to expression
+	InitExpander( const ast::Expr * expr );
+
+	std::vector< ast::ptr< ast::Expr > > operator* ();
+	InitExpander & operator++ ();
+
+	/// builds statement which has the same semantics as a C-style list initializer (for array
+	/// initializers) using callExpr as the base expression to perform initialization.
+	/// Mutates callExpr
+	ast::ptr< ast::Stmt > buildListInit( ast::UntypedExpr * callExpr );
+
+	void addArrayIndex( const ast::Expr * index, const ast::Expr * dimension );
+
+	void clearArrayIndices();
+
+	bool addReference();
+};
+
+} // namespace InitTweak
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/InitTweak/module.mk
===================================================================
--- src/InitTweak/module.mk	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ src/InitTweak/module.mk	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -16,14 +16,14 @@
 
 SRC_INITTWEAK = \
-	InitTweak/GenInit.cc \
-	InitTweak/GenInit.h \
-	InitTweak/InitTweak.cc \
-	InitTweak/InitTweak.h
+	InitTweak/GenInit.cpp \
+	InitTweak/GenInit.hpp \
+	InitTweak/InitTweak.cpp \
+	InitTweak/InitTweak.hpp
 
 SRC += $(SRC_INITTWEAK) \
-	InitTweak/FixGlobalInit.cc \
-	InitTweak/FixGlobalInit.h \
+	InitTweak/FixGlobalInit.cpp \
+	InitTweak/FixGlobalInit.hpp \
 	InitTweak/FixInit.cpp \
-	InitTweak/FixInit.h
+	InitTweak/FixInit.hpp
 
 SRCDEMANGLE += $(SRC_INITTWEAK)
