Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision d22bf87d06423658d00bdc0bc13351ccfbc2adba)
+++ src/AST/Decl.cpp	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -20,4 +20,5 @@
 #include <unordered_map>
 
+#include "CodeGen/FixMain.h"   // for FixMain
 #include "Common/Eval.h"       // for eval
 
@@ -75,4 +76,10 @@
 	}
 	this->type = ftype;
+	// Hack forcing the function "main" to have Cforall linkage to replace
+	// main even if it is inside an extern "C", and also makes sure the
+	// replacing function is always a C function.
+	if ( name == "main" ) {
+		this->linkage = CodeGen::FixMain::getMainLinkage();
+	}
 }
 
@@ -101,4 +108,8 @@
 	}
 	this->type = type;
+	// See note above about this hack.
+	if ( name == "main" ) {
+		this->linkage = CodeGen::FixMain::getMainLinkage();
+	}
 }
 
Index: src/CodeGen/CodeGeneratorNew.cpp
===================================================================
--- src/CodeGen/CodeGeneratorNew.cpp	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
+++ src/CodeGen/CodeGeneratorNew.cpp	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -0,0 +1,1251 @@
+//
+// 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.
+//
+// CodeGeneratorNew.cpp --
+//
+// Author           : Andrew Beach
+// Created On       : Tue Oct 17 15:54:00 2023
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Oct 25 18:28:00 2023
+// Update Count     : 0
+//
+
+#include "CodeGeneratorNew.hpp"
+
+#include "AST/Print.hpp"
+#include "OperatorTable.h"           // for OperatorInfo, operatorLookup
+#include "CodeGen/GenType.h"         // for genType
+#include "Common/ToString.hpp"       // for toString
+#include "Common/UniqueName.h"       // for UniqueName
+
+namespace CodeGen {
+
+int CodeGenerator_new::tabsize = 4;
+
+// The kinds of statements that should be followed by whitespace.
+static bool wantSpacing( ast::Stmt const * stmt ) {
+	return dynamic_cast<ast::IfStmt const *>( stmt )
+		|| dynamic_cast<ast::CompoundStmt const *>( stmt )
+		|| dynamic_cast<ast::WhileDoStmt const *>( stmt )
+		|| dynamic_cast<ast::ForStmt const *>( stmt )
+		|| dynamic_cast<ast::SwitchStmt const *>( stmt );
+}
+
+void CodeGenerator_new::extension( ast::Expr const * expr ) {
+	if ( expr->extension ) output << "__extension__ ";
+}
+
+void CodeGenerator_new::extension( ast::Decl const * decl ) {
+	if ( decl->extension ) output << "__extension__ ";
+}
+
+void CodeGenerator_new::asmName( ast::DeclWithType const * decl ) {
+	if ( auto asmName = decl->asmName.as<ast::ConstantExpr>() ) {
+		output << " asm ( " << asmName->rep << " )";
+	}
+}
+
+CodeGenerator_new::LabelPrinter & CodeGenerator_new::LabelPrinter::operator()(
+		std::vector<ast::Label> const & l ) {
+	labels = &l;
+	return *this;
+}
+
+std::ostream & CodeGenerator_new::LabelPrinter::operator()( std::ostream & output ) const {
+	const std::vector<ast::Label> & labels = *this->labels;
+	for ( const ast::Label & label : labels ) {
+		output << label.name + ": ";
+		this->cg.genAttributes( label.attributes );
+	}
+	return output;
+}
+
+// Using updateLocation at the beginning of a node and endl within a node
+// should become the method of formating.
+void CodeGenerator_new::updateLocation( CodeLocation const & to ) {
+	// Skip if linemarks shouldn't appear or if location is unset.
+	if ( !options.lineMarks || to.isUnset() ) return;
+
+	if ( currentLocation.followedBy( to, 0 ) ) {
+		return;
+	} else if ( currentLocation.followedBy( to, 1 ) ) {
+		output << "\n" << indent;
+		currentLocation.first_line += 1;
+	} else if ( currentLocation.followedBy( to, 2 ) ) {
+		output << "\n\n" << indent;
+		currentLocation.first_line += 2;
+	} else {
+		output << "\n# " << to.first_line << " \"" << to.filename
+		       << "\"\n" << indent;
+		currentLocation = to;
+	}
+	output << std::flush;
+}
+
+void CodeGenerator_new::updateLocation( ast::ParseNode const * to ) {
+	updateLocation( to->location );
+}
+
+std::ostream & CodeGenerator_new::LineEnder::operator()( std::ostream & os ) const {
+	os << "\n" << std::flush;
+	cg.currentLocation.first_line++;
+	return os;
+}
+
+CodeGenerator_new::CodeGenerator_new( std::ostream & os, const Options & options ) :
+		indent( 0, CodeGenerator_new::tabsize ), output( os ),
+		options( options ), printLabels( *this ), endl( *this )
+{}
+
+std::string CodeGenerator_new::mangleName( ast::DeclWithType const * decl ) {
+	// GCC builtins should always be printed unmangled.
+	if ( options.pretty || decl->linkage.is_gcc_builtin ) {
+		return decl->name;
+	} else if ( decl->linkage.is_mangled && decl->mangleName != "" ) {
+		return decl->scopedMangleName();
+	} else {
+		return decl->name;
+	}
+}
+
+void CodeGenerator_new::genAttributes(
+		const std::vector<ast::ptr<ast::Attribute>> & attributes ) {
+	if ( attributes.empty() ) return;
+	output << "__attribute__ ((";
+	for ( auto attr = attributes.begin() ;; ) {
+		output << (*attr)->name;
+		if ( !(*attr)->params.empty() ) {
+			output << "(";
+			genCommaList( (*attr)->params );
+			output << ")";
+		}
+		if ( ++attr == attributes.end() ) break;
+		output << ",";
+	}
+	output << ")) ";
+}
+
+void CodeGenerator_new::previsit( ast::Node const * ) {
+	// All traversal is manual.
+	// TODO: Which means the ast::Pass is just providing a default no visit?
+	visit_children = false;
+}
+
+void CodeGenerator_new::previsit( ast::ParseNode const * node ) {
+	previsit( (ast::Node const *)node );
+	updateLocation( node );
+}
+
+void CodeGenerator_new::postvisit( ast::Node const * node ) {
+	std::stringstream ss;
+	ast::print( ss, node );
+	assertf( false, "Unhandled node reached in CodeGenerator: %s", ss.str().c_str() );
+}
+
+void CodeGenerator_new::previsit( ast::Expr const * expr ) {
+	previsit( (ast::ParseNode const *)expr );
+	GuardAction( [this, expr](){
+		if ( options.printExprTypes && expr->result ) {
+			output << " /* " << genType( expr->result, "", options ) << " */ ";
+		}
+	} );
+}
+
+void CodeGenerator_new::postvisit( ast::FunctionDecl const * decl ) {
+	// Deleted decls should never be used, so don't print them in C.
+	if ( decl->isDeleted && options.genC ) return;
+	extension( decl );
+	genAttributes( decl->attributes );
+
+	handleStorageClass( decl );
+	ast::print( output, decl->funcSpec );
+
+	Options subOptions = options;
+	subOptions.anonymousUnused = decl->stmts;
+
+	std::ostringstream acc;
+	ast::Pass<CodeGenerator_new> subCG( acc, subOptions );
+	// Add the forall clause.
+	// TODO: These probably should be removed by now and the assert used.
+	if ( !decl->type_params.empty() && !options.genC ) {
+		//assertf( !options.genC, "FunctionDecl::forall should not reach code generation." );
+		acc << "forall(";
+		subCG.core.genCommaList( decl->type_params );
+		acc << ")" << std::endl;
+	}
+
+	acc << mangleName( decl );
+
+	if ( 0 == decl->params.size() ) {
+		if ( decl->type->isVarArgs ) {
+			acc << "()";
+		} else {
+			acc << "(void)";
+		}
+	} else {
+		acc << "(";
+		subCG.core.genCommaList( decl->params );
+		if ( decl->type->isVarArgs ) {
+			acc << ", ...";
+		}
+		acc << ")";
+	}
+
+	assert( decl->returns.size() < 2 );
+	if ( 1 == decl->returns.size() ) {
+		ast::ptr<ast::Type> const & type = decl->returns[0]->get_type();
+		output << genTypeNoAttr( type, acc.str(), subOptions );
+	} else {
+		output << "void " + acc.str();
+	}
+
+	asmName( decl );
+
+	if ( decl->stmts ) {
+		decl->stmts->accept( *visitor );
+	}
+	if ( decl->isDeleted ) {
+		output << " = void";
+	}
+}
+
+//void CodeGenerator_new::postvisit( ast::ObjectDecl const * decl_ ) {
+ast::ObjectDecl const * CodeGenerator_new::postvisit(
+		ast::ObjectDecl const * decl ) {
+	// Deleted decls should never be used, so don't print them in C.
+	if ( decl->isDeleted && options.genC ) return decl;
+
+	// GCC allows an empty declarator (no name) for bit-fields and C
+	// states: 6.7.2.1 Structure and union specifiers, point 4, page 113:
+	// If the (bit field) value is zero, the declaration shall have no
+	// declarator. For anything else, the anonymous name refers to the
+	// anonymous object for plan9 inheritance.
+	if ( decl->name.empty() && options.genC && !decl->bitfieldWidth ) {
+		// TODO: Should this be changed in a pervious pass?
+		auto mutDecl = ast::mutate( decl );
+		// Only generate an anonymous name when generating C code,
+		// otherwise it clutters the output too much.
+		static UniqueName name = { "__anonymous_object" };
+		mutDecl->name = name.newName();
+		// Stops unused parameter warnings.
+		if ( options.anonymousUnused ) {
+			mutDecl->attributes.push_back( new ast::Attribute( "unused" ) );
+		}
+		decl = mutDecl;
+	}
+
+	extension( decl );
+	genAttributes( decl->attributes );
+
+	handleStorageClass( decl );
+	output << genType( decl->type, mangleName( decl ),
+		Options( options.pretty, options.genC, false, false ) );
+
+	asmName( decl );
+
+	if ( decl->init ) {
+		output << " = ";
+		decl->init->accept( *visitor );
+	}
+	if ( decl->isDeleted ) {
+		output << " = void";
+	}
+
+	if ( decl->bitfieldWidth ) {
+		output << ":";
+		decl->bitfieldWidth->accept( *visitor );
+	}
+	return decl;
+}
+
+void CodeGenerator_new::handleStorageClass( ast::DeclWithType const * decl ) {
+	if ( decl->storage.any() ) {
+		ast::print( output, decl->storage );
+	}
+}
+
+void CodeGenerator_new::handleAggregate(
+		ast::AggregateDecl const * decl, std::string const & kind ) {
+	if ( !decl->params.empty() && !options.genC ) {
+		output << "forall(";
+		genCommaList( decl->params );
+		output << ")\n" << indent << std::flush;
+	}
+
+	output << kind;
+	genAttributes( decl->attributes );
+	output << decl->name;
+
+	if ( decl->body ) {
+		auto & members = decl->members;
+		output << " {" << endl;
+
+		++indent;
+		for ( auto & member : members ) {
+			output << indent;
+			member->accept( *visitor );
+			output << ";" << endl;
+		}
+		--indent;
+
+		output << indent << "}";
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::StructDecl const * decl ) {
+	extension( decl );
+	handleAggregate( decl, "struct " );
+}
+
+void CodeGenerator_new::postvisit( ast::UnionDecl const * decl ) {
+	extension( decl );
+	handleAggregate( decl, "union " );
+}
+
+template<typename pass_type>
+inline void genEnumInitializer( ast::Pass<pass_type> * visitor,
+		ast::Type const * baseType, std::ostream & output,
+		ast::Init const * init, long long * curVal, Options options ) {
+	auto baseTypeAsBasic = dynamic_cast<ast::BasicType const *>( baseType );
+	// Value is provided.
+	if ( init ) {
+		output << " = (" << genType( baseType, "", options ) << ")";
+		init->accept( *visitor );
+		// If it is an integral type and initilizer offered,
+		// need to update the curVal.
+		if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
+			ast::Expr const * expr = ((ast::SingleInit const *)(init))->value;
+			// Unwrap introduced cast.
+			while ( auto temp = dynamic_cast<ast::CastExpr const *>( expr ) ) {
+				expr = temp->arg;
+			}
+			*curVal = ((ast::ConstantExpr const *)(expr))->intValue() + 1;
+		}
+	// Generate next value from previous value.
+	} else if ( baseTypeAsBasic && baseTypeAsBasic->isInteger() ) {
+		output << " = (" << genType( baseType, "", options ) << ")";
+		output << (*curVal)++;
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::EnumDecl const * decl ) {
+	extension( decl );
+	auto members = decl->members;
+	if ( decl->base && !members.empty() ) {
+		long long curVal = 0;
+		for ( auto member : members ) {
+			auto obj = member.strict_as<ast::ObjectDecl>();
+			output << "static ";
+			output << genType( decl->base, mangleName( obj ), options );
+			genEnumInitializer( visitor, decl->base, output, obj->init, &curVal, options );
+			output << ";" << endl;
+		}
+	} else {
+		output << "enum ";
+		genAttributes( decl->attributes );
+
+		output << decl->name;
+
+		if ( !members.empty() ) {
+			output << " {" << endl;
+
+			++indent;
+			for ( auto member : members ) {
+				auto obj = member.strict_as<ast::ObjectDecl>();
+				output << indent << mangleName( obj );
+				if ( obj->init ) {
+					output << " = ";
+					obj->init->accept( *visitor );
+				}
+				output << "," << endl;
+			}
+			--indent;
+
+			output << indent << "}";
+		}
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::TraitDecl const * decl ) {
+	assertf( !options.genC, "TraitDecls should not reach code generation." );
+	extension( decl );
+	handleAggregate( decl, "trait " );
+}
+
+void CodeGenerator_new::postvisit( ast::TypedefDecl const * decl ) {
+	assertf( !options.genC, "Typedefs should not reach code generation." );
+	output << "typedef " << genType( decl->base, decl->name, options ) << endl;
+}
+
+void CodeGenerator_new::postvisit( ast::TypeDecl const * decl ) {
+	assertf( !options.genC, "TypeDecls should not reach code generation." );
+	output << decl->genTypeString() << " " << decl->name;
+	if ( decl->sized ) {
+		output << " | sized(" << decl->name << ")";
+	}
+	if ( !decl->assertions.empty() ) {
+		output << " | { ";
+		for ( ast::DeclWithType const * assert : decl->assertions ) {
+			assert->accept( *visitor );
+			output << "; ";
+		}
+		output << " }";
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::StaticAssertDecl const * decl ) {
+	output << "_Static_assert(";
+	decl->cond->accept( *visitor );
+	output << ", ";
+	decl->msg->accept( *visitor );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::Designation const * designation ) {
+	auto designators = designation->designators;
+	if ( 0 == designators.size() ) return;
+	for ( ast::ptr<ast::Expr> const & des : designators ) {
+		// If the expression is a NameExpr or VariableExpr, then it is a field.
+		if ( des.as<ast::NameExpr>() || des.as<ast::VariableExpr>() ) {
+			output << ".";
+			des->accept( *visitor );
+		// Otherwise, it is a ConstantExpr or CastExpr, then it is an index.
+		} else {
+			output << "[";
+			des->accept( *visitor );
+			output << "]";
+		}
+	}
+	output << " = ";
+}
+
+void CodeGenerator_new::postvisit( ast::SingleInit const * init ) {
+	init->value->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::ListInit const * init ) {
+	auto initBegin = init->initializers.begin();
+	auto initEnd = init->initializers.end();
+	auto desigBegin = init->designations.begin();
+	auto desigEnd = init->designations.end();
+
+	output << "{ ";
+	if ( initBegin != initEnd ) while (true) {
+		(*desigBegin)->accept( *visitor );
+		(*initBegin)->accept( *visitor );
+		++initBegin, ++desigBegin;
+		if ( initBegin == initEnd ) break;
+		output << ", ";
+	}
+	output << " }";
+	assertf( initBegin == initEnd && desigBegin == desigEnd,
+		"Initializers and designators not the same length. %s", toCString( init ) );
+}
+
+void CodeGenerator_new::postvisit( ast::ConstructorInit const * init ) {
+	assertf( !options.genC, "ConstructorInit nodes should not reach code generation." );
+	// This isn't actual code, but labels the constructor/destructor pairs.
+	output << "<ctorinit>{" << endl << ++indent << "ctor: ";
+	if ( init->ctor ) init->ctor->accept( *visitor );
+	output << ", " << endl << indent << "dtor: ";
+	if ( init->dtor ) init->dtor->accept( *visitor );
+	output << endl << --indent << "}";
+}
+
+void CodeGenerator_new::postvisit( ast::ApplicationExpr const * expr ) {
+	extension( expr );
+	if ( auto var = expr->func.as<ast::VariableExpr>() ) {
+		const OperatorInfo * opInfo;
+		if ( var->var->linkage == ast::Linkage::Intrinsic &&
+				( opInfo = operatorLookup( var->var->name ) ) ) {
+			auto arg = expr->args.begin();
+			switch ( opInfo->type ) {
+			case OT_INDEX:
+				assert( 2 == expr->args.size() );
+				(*arg++)->accept( *visitor );
+				output << "[";
+				(*arg)->accept( *visitor );
+				output << "]";
+				break;
+
+			// There are no intrinsic definitions of the function call operator.
+			case OT_CALL:
+				assert( false );
+				break;
+
+			case OT_CTOR:
+			case OT_DTOR:
+				// No-op constructor, but run the internal expression.
+				if ( 1 == expr->args.size() ) {
+					output << "(";
+					(*arg++)->accept( *visitor );
+					output << ") /* " << opInfo->inputName << " */";
+				// These are all implemented as some form of assignment.
+				} else if ( 2 == expr->args.size() ) {
+					output << "(";
+					(*arg++)->accept( *visitor );
+					output << opInfo->symbol;
+					(*arg)->accept( *visitor );
+					output << ") /* " << opInfo->inputName << " */";
+				// No constructors with 0 or more than 2 parameters.
+				} else {
+					assert( false );
+				}
+				break;
+
+			case OT_PREFIX:
+			case OT_PREFIXASSIGN:
+				assert( 1 == expr->args.size() );
+				output << "(" << opInfo->symbol;
+				(*arg)->accept( *visitor );
+				output << ")";
+				break;
+
+			case OT_POSTFIX:
+			case OT_POSTFIXASSIGN:
+				assert( 1 == expr->args.size() );
+				(*arg)->accept( *visitor );
+				output << opInfo->symbol;
+				break;
+
+			case OT_INFIX:
+			case OT_INFIXASSIGN:
+				assert( 2 == expr->args.size() );
+				output << "(";
+				(*arg++)->accept( *visitor );
+				output << opInfo->symbol;
+				(*arg)->accept( *visitor );
+				output << ")";
+				break;
+
+			// There are no intrinsic definitions of 0/1 or label address
+			// as function.
+			case OT_CONSTANT:
+			case OT_LABELADDRESS:
+				assert( false );
+			}
+		// TODO: This is a work-around to make it a constant until a proper
+		// constexpr solution is created.
+		} else if ( var->var->linkage == ast::Linkage::BuiltinCFA &&
+				var->var->name == "intptr" ) {
+			output << "((void*)";
+			auto arg = expr->args.begin();
+			(*arg++)->accept( *visitor );
+			output << ")";
+		} else {
+			var->accept( *visitor );
+			output << "(";
+			genCommaList( expr->args );
+			output << ")";
+		}
+	} else {
+		expr->func->accept( *visitor );
+		output << "(";
+		genCommaList( expr->args );
+		output << ")";
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::UntypedExpr const * expr ) {
+	extension( expr );
+	if ( auto name = expr->func.as<ast::NameExpr>() ) {
+		if ( const OperatorInfo * opInfo = operatorLookup( name->name ) ) {
+			auto arg = expr->args.begin();
+			switch ( opInfo->type ) {
+			case OT_INDEX:
+				assert( 2 == expr->args.size() );
+				(*arg++)->accept( *visitor );
+				output << "[";
+				(*arg)->accept( *visitor );
+				output << "]";
+				break;
+
+			case OT_CALL:
+				assert( false );
+
+			case OT_CTOR:
+			case OT_DTOR:
+				// No-op constructor, but run the internal expression.
+				if ( 1 == expr->args.size() ) {
+					output << "(";
+					(*arg++)->accept( *visitor );
+					output << ")";
+				// These are all implemented as some form of assignment.
+				} else if ( 2 == expr->args.size() ) {
+					output << "(";
+					(*arg++)->accept( *visitor );
+					output << opInfo->symbol;
+					(*arg)->accept( *visitor );
+					output << ") /* " << opInfo->inputName << " */";
+				// No constructors with 0 or more than 2 parameters.
+				} else {
+					assertf( !options.genC, "UntypedExpr constructor/destructor with 0 or more than 2 parameters." );
+					output << "(";
+					(*arg++)->accept( *visitor );
+					output << opInfo->symbol << "{ ";
+					genCommaList( arg, expr->args.end() );
+					output << "}) /* " << opInfo->inputName << " */";
+				}
+				break;
+
+			case OT_PREFIX:
+			case OT_PREFIXASSIGN:
+			case OT_LABELADDRESS:
+				assert( 1 == expr->args.size() );
+				output << "(" << opInfo->symbol;
+				(*arg)->accept( *visitor );
+				output << ")";
+				break;
+
+			case OT_POSTFIX:
+			case OT_POSTFIXASSIGN:
+				assert( 1 == expr->args.size() );
+				(*arg)->accept( *visitor );
+				output << opInfo->symbol;
+				break;
+
+			case OT_INFIX:
+			case OT_INFIXASSIGN:
+				assert( 2 == expr->args.size() );
+				output << "(";
+				(*arg++)->accept( *visitor );
+				output << opInfo->symbol;
+				(*arg)->accept( *visitor );
+				output << ")";
+				break;
+
+			// There are no intrinsic definitions of 0/1 or label address
+			// as function.
+			case OT_CONSTANT:
+				assert( false );
+			}
+		// builtin routines
+		} else {
+			name->accept( *visitor );
+			output << "(";
+			genCommaList( expr->args );
+			output << ")";
+		}
+	} else {
+		expr->func->accept( *visitor );
+		output << "(";
+		genCommaList( expr->args );
+		output << ")";
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::RangeExpr const * expr ) {
+	expr->low->accept( *visitor );
+	output << " ... ";
+	expr->high->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::NameExpr const * expr ) {
+	extension( expr );
+	if ( const OperatorInfo * opInfo = operatorLookup( expr->name ) ) {
+		if ( OT_CONSTANT == opInfo->type ) {
+			output << opInfo->symbol;
+		} else {
+			output << opInfo->outputName;
+		}
+	} else {
+		output << expr->name;
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::DimensionExpr const * expr ) {
+	extension( expr );
+	output << "/*non-type*/" << expr->name;
+}
+
+void CodeGenerator_new::postvisit( ast::AddressExpr const * expr ) {
+	extension( expr );
+	output << "(&";
+	expr->arg->accept( *visitor );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::LabelAddressExpr const * expr ) {
+	extension( expr );
+	output << "(&&" << expr->arg << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::CastExpr const * expr ) {
+	extension( expr );
+	output << "(";
+	if ( expr->result->isVoid() ) {
+		output << "(void)";
+	} else {
+		output << "(";
+		output << genType( expr->result, "", options );
+		output << ")";
+	}
+	expr->arg->accept( *visitor );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::KeywordCastExpr const * expr ) {
+	assertf( !options.genC, "KeywordCastExpr should not reach code generation." );
+	extension( expr );
+	output << "((" << expr->targetString() << " &)";
+	expr->arg->accept( *visitor );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::VirtualCastExpr const * expr ) {
+	assertf( !options.genC, "VirtualCastExpr should not reach code generation." );
+	extension( expr );
+	// TODO: Is this busted?
+	output << "(virtual ";
+	expr->arg->accept( *visitor );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::UntypedMemberExpr const * expr ) {
+	assertf( !options.genC, "UntypedMemberExpr should not reach code generation." );
+	extension( expr );
+	expr->aggregate->accept( *visitor );
+	output << ".";
+	expr->member->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::MemberExpr const * expr ) {
+	extension( expr );
+	expr->aggregate->accept( *visitor );
+	output << "." << mangleName( expr->member );
+}
+
+void CodeGenerator_new::postvisit( ast::VariableExpr const * expr ) {
+	extension( expr );
+	const OperatorInfo * opInfo;
+	if ( dynamic_cast<ast::ZeroType const *>( expr->var->get_type() ) ) {
+		output << "0";
+	} else if ( expr->var->linkage == ast::Linkage::Intrinsic
+			&& ( opInfo = operatorLookup( expr->var->name ) )
+			&& opInfo->type == OT_CONSTANT ) {
+		output << opInfo->symbol;
+	} else {
+		output << mangleName( expr->var );
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::ConstantExpr const * expr ) {
+	extension( expr );
+	output << expr->rep;
+}
+
+void CodeGenerator_new::postvisit( ast::SizeofExpr const * expr ) {
+	extension( expr );
+	output << "sizeof(";
+	if ( expr->type ) {
+		output << genType( expr->type, "", options );
+	} else {
+		expr->expr->accept( *visitor );
+	}
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::AlignofExpr const * expr ) {
+	// Using the GCC extension to avoid changing the std to C11.
+	extension( expr );
+	output << "__alignof__(";
+	if ( expr->type ) {
+		output << genType( expr->type, "", options );
+	} else {
+		expr->expr->accept( *visitor );
+	}
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::UntypedOffsetofExpr const * expr ) {
+	assertf( !options.genC, "UntypedOffsetofExpr should not reach code generation." );
+	output << "offsetof(";
+	output << genType( expr->type, "", options );
+	output << ", " << expr->member;
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::OffsetofExpr const * expr ) {
+	// Use GCC builtin
+	output << "__builtin_offsetof(";
+	output << genType( expr->type, "", options );
+	output << ", " << mangleName( expr->member );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::OffsetPackExpr const * expr ) {
+	assertf( !options.genC, "OffsetPackExpr should not reach code generation." );
+	output << "__CFA_offsetpack(" << genType( expr->type, "", options ) << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::LogicalExpr const * expr ) {
+	extension( expr );
+	output << "(";
+	expr->arg1->accept( *visitor );
+	output << ( ( expr->isAnd ) ? " && " : " || " );
+	expr->arg2->accept( *visitor );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::ConditionalExpr const * expr ) {
+	extension( expr );
+	output << "(";
+	expr->arg1->accept( *visitor );
+	output << " ? ";
+	expr->arg2->accept( *visitor );
+	output << " : ";
+	expr->arg3->accept( *visitor );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::CommaExpr const * expr ) {
+	extension( expr );
+	output << "(";
+	if ( options.genC ) {
+		// arg1 of a comma expression is never used, so it can be safely cast
+		// to void to reduce gcc warnings.
+		ast::ptr<ast::Expr> arg1 = new ast::CastExpr( expr->location, expr->arg1 );
+		arg1->accept( *visitor );
+	} else {
+		expr->arg1->accept( *visitor );
+	}
+	output << " , ";
+	expr->arg2->accept( *visitor );
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::TupleAssignExpr const * expr ) {
+	assertf( !options.genC, "TupleAssignExpr should not reach code generation." );
+	expr->stmtExpr->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::UntypedTupleExpr const * expr ) {
+	assertf( !options.genC, "UntypedTupleExpr should not reach code generation." );
+	extension( expr );
+	output << "[";
+	genCommaList( expr->exprs );
+	output << "]";
+}
+
+void CodeGenerator_new::postvisit( ast::TupleExpr const * expr ) {
+	assertf( !options.genC, "TupleExpr should not reach code generation." );
+	extension( expr );
+	output << "[";
+	genCommaList( expr->exprs );
+	output << "]";
+}
+
+void CodeGenerator_new::postvisit( ast::TupleIndexExpr const * expr ) {
+	assertf( !options.genC, "TupleIndexExpr should not reach code generation." );
+	extension( expr );
+	expr->tuple->accept( *visitor );
+	output << "." << expr->index;
+}
+
+void CodeGenerator_new::postvisit( ast::TypeExpr const * expr ) {
+	// TODO: Should there be an assertion there?
+	if ( !options.genC ) {
+		output << genType( expr->type, "", options );
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::AsmExpr const * expr ) {
+	if ( !expr->inout.empty() ) {
+		output << "[ " << expr->inout << " ] ";
+	}
+	expr->constraint->accept( *visitor );
+	output << " ( ";
+	expr->operand->accept( *visitor );
+	output << " )";
+}
+
+void CodeGenerator_new::postvisit( ast::CompoundLiteralExpr const * expr ) {
+	//assert( expr->result && dynamic_cast<ast::ListInit const *>( expr->init ) );
+	assert( expr->result && expr->init.as<ast::ListInit>() );
+	output << "(" << genType( expr->result, "", options ) << ")";
+	expr->init->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::UniqueExpr const * expr ) {
+	assertf( !options.genC, "UniqueExpr should not reach code generation." );
+	output << "unq<" << expr->id << ">{ ";
+	expr->expr->accept( *visitor );
+	output << " }";
+}
+
+void CodeGenerator_new::postvisit( ast::StmtExpr const * expr ) {
+	auto stmts = expr->stmts->kids;
+	output << "({" << endl;
+	++indent;
+	unsigned int numStmts = stmts.size();
+	unsigned int i = 0;
+	for ( ast::ptr<ast::Stmt> const & stmt : stmts ) {
+		output << indent << printLabels( stmt->labels );
+		if ( i + 1 == numStmts ) {
+			// Last statement in a statement expression needs to be handled
+			// specially - cannot cast to void, otherwise the expression
+			// statement has no value.
+			if ( ast::ExprStmt const * exprStmt = stmt.as<ast::ExprStmt>() ) {
+				exprStmt->expr->accept( *visitor );
+				output << ";" << endl;
+				++i;
+				break;
+			}
+		}
+		stmt->accept( *visitor );
+		output << endl;
+		if ( wantSpacing( stmt ) ) output << endl;
+		++i;
+	}
+	--indent;
+	output << indent << "})";
+}
+
+void CodeGenerator_new::postvisit( ast::ConstructorExpr const * expr ) {
+	assertf( !options.genC, "ConstructorExpr should not reach code generation." );
+	expr->callExpr->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::DeletedExpr const * expr ) {
+	assertf( !options.genC, "DeletedExpr should not reach code generation." );
+	expr->expr->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::DefaultArgExpr const * expr ) {
+	assertf( !options.genC, "DefaultArgExpr should not reach code generation." );
+	expr->expr->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::GenericExpr const * expr ) {
+	assertf( !options.genC, "GenericExpr should not reach code generation." );
+	output << "_Generic(";
+	expr->control->accept( *visitor );
+	output << ", ";
+	unsigned int numAssocs = expr->associations.size();
+	unsigned int i = 0;
+	for ( const ast::GenericExpr::Association & assoc : expr->associations ) {
+		if ( nullptr == assoc.type ) {
+			output << "default: ";
+		} else {
+			output << genType( assoc.type, "", options ) << ": ";
+		}
+		assoc.expr->accept( *visitor );
+		++i;
+		if ( i != numAssocs ) output << ", ";
+	}
+	output << ")";
+}
+
+void CodeGenerator_new::postvisit( ast::CompoundStmt const * stmt ) {
+	output << "{" << endl;
+
+	++indent;
+	for ( auto kid : stmt->kids ) {
+		output << indent << printLabels( kid->labels );
+		kid->accept( *visitor );
+		output << endl;
+		if ( wantSpacing( kid ) ) output << endl;
+	}
+	--indent;
+
+	output << indent << "}";
+}
+
+void CodeGenerator_new::postvisit( ast::ExprStmt const * stmt ) {
+	assert( stmt );
+	// Cast the top-level expression to void to reduce gcc warnings.
+	if ( options.genC ) {
+		ast::ptr<ast::Expr> expr = new ast::CastExpr( stmt->location, stmt->expr );
+		expr->accept( *visitor );
+	} else {
+		stmt->expr->accept( *visitor );
+	}
+	output << ";";
+}
+
+void CodeGenerator_new::postvisit( ast::AsmStmt const * stmt ) {
+	output << "asm ";
+	if ( stmt->isVolatile ) output << "volatile ";
+	if ( !stmt->gotoLabels.empty() ) output << "goto ";
+	output << "( ";
+	if ( stmt->instruction ) stmt->instruction->accept( *visitor );
+	output << " : ";
+	genCommaList( stmt->output );
+	output << " : ";
+	genCommaList( stmt->input );
+	output << " : ";
+	genCommaList( stmt->clobber );
+	if ( !stmt->gotoLabels.empty() ) {
+		output << " : ";
+		auto it = stmt->gotoLabels.begin();
+		while (true) {
+			output << *it++;
+			if ( stmt->gotoLabels.end() == it ) break;
+			output << ", ";
+		}
+	}
+	output << " );";
+}
+
+void CodeGenerator_new::postvisit( ast::AsmDecl const * decl ) {
+	output << "asm ";
+	ast::AsmStmt const * stmt = decl->stmt;
+	output << "( ";
+	if ( stmt->instruction ) stmt->instruction->accept( *visitor );
+	output << " )";
+}
+
+void CodeGenerator_new::postvisit( ast::DirectiveDecl const * decl ) {
+	// endl prevents spaces before the directive.
+	output << endl << decl->stmt->directive;
+}
+
+void CodeGenerator_new::postvisit( ast::DirectiveStmt const * stmt ) {
+	// endl prevents spaces before the directive.
+	output << endl << stmt->directive;
+}
+
+void CodeGenerator_new::postvisit( ast::IfStmt const * stmt ) {
+	output << "if ( ";
+	stmt->cond->accept( *visitor );
+	output << " ) ";
+
+	stmt->then->accept( *visitor );
+
+	if ( nullptr != stmt->else_ ) {
+		output << " else ";
+		stmt->else_->accept( *visitor );
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::SwitchStmt const * stmt ) {
+	output << "switch ( ";
+	stmt->cond->accept( *visitor );
+	output << " ) ";
+
+	output << "{";
+	++indent;
+	for ( auto node : stmt->cases ) {
+		node->accept( *visitor );
+	}
+	--indent;
+	output << indent << "}";
+}
+
+void CodeGenerator_new::postvisit( ast::CaseClause const * clause ) {
+	updateLocation( clause );
+	output << indent;
+	if ( clause->isDefault() ) {
+		output << "default";
+	} else {
+		output << "case ";
+		clause->cond->accept( *visitor );
+	}
+	output << ":" << endl;
+
+	++indent;
+	for ( auto stmt : clause->stmts ) {
+		output << indent << printLabels( stmt->labels ) ;
+		stmt->accept( *visitor );
+		output << endl;
+	}
+	--indent;
+}
+
+void CodeGenerator_new::postvisit( ast::BranchStmt const * stmt ) {
+	switch ( stmt->kind ) {
+	case ast::BranchStmt::Goto:
+		if ( !stmt->target.empty() ) {
+			output << "goto " << stmt->target;
+		} else if ( nullptr != stmt->computedTarget ) {
+			output << "goto *";
+			stmt->computedTarget->accept( *visitor );
+		}
+		break;
+	case ast::BranchStmt::Break:
+		output << "break";
+		break;
+	case ast::BranchStmt::Continue:
+		output << "continue";
+		break;
+	case ast::BranchStmt::FallThrough:
+	case ast::BranchStmt::FallThroughDefault:
+		assertf( !options.genC, "fallthru should not reach code generation." );
+		output << "fallthru";
+		break;
+	default:
+		assertf( false, "Bad BranchStmt value." );
+	}
+	// Print branch target for labelled break/continue/fallthru in debug mode.
+	if ( !options.genC && stmt->kind != ast::BranchStmt::Goto ) {
+		if ( !stmt->target.empty() ) {
+			output << " " << stmt->target;
+		} else if ( stmt->kind == ast::BranchStmt::FallThrough ) {
+			output << " default";
+		}
+	}
+	output << ";";
+}
+
+void CodeGenerator_new::postvisit( ast::ReturnStmt const * stmt ) {
+	output << "return ";
+	if ( stmt->expr ) stmt->expr->accept( *visitor );
+	output << ";";
+}
+
+void CodeGenerator_new::postvisit( ast::ThrowStmt const * stmt ) {
+	assertf( !options.genC, "ThrowStmt should not reach code generation." );
+
+	output << ((stmt->kind == ast::Terminate) ? "throw" : "throwResume");
+	if ( stmt->expr ) {
+		output << " ";
+		stmt->expr->accept( *visitor );
+	}
+	if ( stmt->target ) {
+		output << " _At ";
+		stmt->target->accept( *visitor );
+	}
+	output << ";";
+}
+
+void CodeGenerator_new::postvisit( ast::CatchClause const * stmt ) {
+	assertf( !options.genC, "CatchClause should not reach code generation." );
+
+	output << ((stmt->kind == ast::Terminate) ? "catch" : "catchResume");
+	output << "( ";
+	stmt->decl->accept( *visitor );
+	if ( stmt->cond ) {
+		output << " ; ";
+		stmt->cond->accept( *visitor );
+	}
+	output << " ) ";
+	stmt->body->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::WaitForStmt const * stmt ) {
+	assertf( !options.genC, "WaitforStmt should not reach code generation." );
+
+	bool first = true;
+	for ( ast::ptr<ast::WaitForClause> const & clause : stmt->clauses ) {
+		if (first) { output << "or "; first = false; }
+		if ( clause->when_cond ) {
+			output << "when(";
+			stmt->timeout_cond->accept( *visitor );
+			output << ") ";
+		}
+		output << "waitfor(";
+		clause->target->accept( *visitor );
+		for ( ast::ptr<ast::Expr> const & expr : clause->target_args ) {
+			output << ",";
+			expr->accept( *visitor );
+		}
+		output << ") ";
+		clause->stmt->accept( *visitor );
+	}
+
+	if ( stmt->timeout_stmt ) {
+		output << "or ";
+		if ( stmt->timeout_cond ) {
+			output << "when(";
+			stmt->timeout_cond->accept( *visitor );
+			output << ") ";
+		}
+		output << "timeout(";
+		stmt->timeout_time->accept( *visitor );
+		output << ") ";
+		stmt->timeout_stmt->accept( *visitor );
+	}
+
+	if ( stmt->else_stmt ) {
+		output << "or ";
+		if ( stmt->else_cond ) {
+			output << "when(";
+			stmt->else_cond->accept( *visitor );
+			output << ")";
+		}
+		output << "else ";
+		stmt->else_stmt->accept( *visitor );
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::WithStmt const * stmt ) {
+	assertf( !options.genC, "WithStmt should not reach code generation." );
+
+	output << "with ( ";
+	genCommaList( stmt->exprs );
+	output << " ) ";
+	stmt->stmt->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::WhileDoStmt const * stmt ) {
+	if ( stmt->isDoWhile ) {
+		output << "do";
+	} else {
+		output << "while (";
+		stmt->cond->accept( *visitor );
+		output << ")";
+	}
+	output << " ";
+
+	output << CodeGenerator_new::printLabels( stmt->body->labels );
+	stmt->body->accept( *visitor );
+
+	output << indent;
+
+	if ( stmt->isDoWhile ) {
+		output << " while (";
+		stmt->cond->accept( *visitor );
+		output << ");";
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::ForStmt const * stmt ) {
+	// Initializer is always hoised so don't generate it.
+	// TODO: Do an assertion check?
+	output << "for (;";
+
+	if ( nullptr != stmt->cond ) {
+		stmt->cond->accept( *visitor );
+	}
+	output << ";";
+
+	if ( nullptr != stmt->inc ) {
+		// cast the top-level expression to void to reduce gcc warnings.
+		ast::Expr * expr = new ast::CastExpr( stmt->inc );
+		expr->accept( *visitor );
+	}
+	output << ") ";
+
+	if ( nullptr != stmt->body ) {
+		output << printLabels( stmt->body->labels );
+		stmt->body->accept( *visitor );
+	}
+}
+
+void CodeGenerator_new::postvisit( ast::NullStmt const * ) {
+	output << "/* null statement */ ;";
+}
+
+void CodeGenerator_new::postvisit( ast::DeclStmt const * stmt ) {
+	stmt->decl->accept( *visitor );
+
+	if ( doSemicolon( stmt->decl ) ) output << ";";
+}
+
+void CodeGenerator_new::postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
+	assertf( !options.genC, "ImplicitCtorCtorStmt should not reach code generation." );
+	stmt->callStmt->accept( *visitor );
+}
+
+void CodeGenerator_new::postvisit( ast::MutexStmt const * stmt ) {
+	assertf( !options.genC, "MutexStmt should not reach code generation." );
+	// TODO: But this isn't what a mutex statement looks like.
+	stmt->stmt->accept( *visitor );
+}
+
+//std::string genName( ast::DeclWithType const * decl ) {}
+
+} // namespace CodeGen
Index: src/CodeGen/CodeGeneratorNew.hpp
===================================================================
--- src/CodeGen/CodeGeneratorNew.hpp	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
+++ src/CodeGen/CodeGeneratorNew.hpp	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -0,0 +1,190 @@
+//
+// 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.
+//
+// CodeGeneratorNew.hpp --
+//
+// Author           : Andrew Beach
+// Created On       : Tue Oct 17 15:54:00 2023
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Oct 25 17:56:00 2023
+// Update Count     : 0
+//
+
+#pragma once
+
+#include <ostream>               // for ostream, operator<<
+
+#include "AST/Fwd.hpp"
+#include "AST/Pass.hpp"          // for WithGuards, WithShortCircuiting, ...
+#include "CodeGen/Options.h"     // for Options
+
+
+namespace CodeGen {
+
+#warning Remove the _new when old version is removed.
+struct CodeGenerator_new :
+		public ast::WithGuards,
+		public ast::WithShortCircuiting,
+		public ast::WithVisitorRef<CodeGenerator_new> {
+	CodeGenerator_new( std::ostream & out, Options const & options );
+
+	// Turn off visit_children for all nodes.
+	void previsit( ast::Node const * );
+	void previsit( ast::ParseNode const * );
+
+	// Error for unhandled node types.
+	void postvisit( ast::Node const * );
+
+	// Print type for all expressions.
+	void previsit( ast::Expr const * );
+
+	void postvisit( ast::StructDecl const * );
+	void postvisit( ast::FunctionDecl const * );
+	// Yes, there is one visit that does modify the ast.
+	ast::ObjectDecl const * postvisit( ast::ObjectDecl const * );
+	void postvisit( ast::UnionDecl const * );
+	void postvisit( ast::EnumDecl const * );
+	void postvisit( ast::TraitDecl const * );
+	void postvisit( ast::TypedefDecl const * );
+	void postvisit( ast::TypeDecl const * );
+	void postvisit( ast::StaticAssertDecl const * );
+
+	void postvisit( ast::Designation const * );
+	void postvisit( ast::SingleInit const * );
+	void postvisit( ast::ListInit const * );
+	void postvisit( ast::ConstructorInit const * );
+
+	void postvisit( ast::ApplicationExpr const * );
+	void postvisit( ast::UntypedExpr const * );
+	void postvisit( ast::RangeExpr const * );
+	void postvisit( ast::NameExpr const * );
+	void postvisit( ast::AddressExpr const * );
+	void postvisit( ast::LabelAddressExpr const * );
+	void postvisit( ast::CastExpr const * );
+	void postvisit( ast::KeywordCastExpr const * );
+	void postvisit( ast::VirtualCastExpr const * );
+	void postvisit( ast::UntypedMemberExpr const * );
+	void postvisit( ast::MemberExpr const * );
+	void postvisit( ast::VariableExpr const * );
+	void postvisit( ast::ConstantExpr const * );
+	void postvisit( ast::SizeofExpr const * );
+	void postvisit( ast::AlignofExpr const * );
+	void postvisit( ast::UntypedOffsetofExpr const * );
+	void postvisit( ast::OffsetofExpr const * );
+	void postvisit( ast::OffsetPackExpr const * );
+	void postvisit( ast::LogicalExpr const * );
+	void postvisit( ast::ConditionalExpr const * );
+	void postvisit( ast::CommaExpr const * );
+	void postvisit( ast::CompoundLiteralExpr const * );
+	void postvisit( ast::UniqueExpr const * );
+	void postvisit( ast::TupleAssignExpr const * );
+	void postvisit( ast::UntypedTupleExpr const * );
+	void postvisit( ast::TupleExpr const * );
+	void postvisit( ast::TupleIndexExpr const * );
+	void postvisit( ast::TypeExpr const * );
+	void postvisit( ast::DimensionExpr const * );
+	void postvisit( ast::AsmExpr const * );
+	void postvisit( ast::StmtExpr const * );
+	void postvisit( ast::ConstructorExpr const * );
+	void postvisit( ast::DeletedExpr const * );
+	void postvisit( ast::DefaultArgExpr const * );
+	void postvisit( ast::GenericExpr const * );
+
+	void postvisit( ast::CompoundStmt const * );
+	void postvisit( ast::ExprStmt const * );
+	void postvisit( ast::AsmStmt const * );
+	void postvisit( ast::DirectiveStmt const* );
+	void postvisit( ast::AsmDecl const * );
+	void postvisit( ast::DirectiveDecl const * );
+	void postvisit( ast::IfStmt const * );
+	void postvisit( ast::SwitchStmt const * );
+	void postvisit( ast::CaseClause const * );
+	void postvisit( ast::BranchStmt const * );
+	void postvisit( ast::ReturnStmt const * );
+	void postvisit( ast::ThrowStmt const * );
+	void postvisit( ast::CatchClause const * );
+	void postvisit( ast::WaitForStmt const * );
+	void postvisit( ast::WithStmt const * );
+	void postvisit( ast::WhileDoStmt const * );
+	void postvisit( ast::ForStmt const * );
+	void postvisit( ast::NullStmt const * );
+	void postvisit( ast::DeclStmt const * );
+	void postvisit( ast::ImplicitCtorDtorStmt const * );
+	void postvisit( ast::MutexStmt const * stmt );
+
+private:
+	/// Custom local implementation of endl that updates print location.
+	struct LineEnder {
+		CodeGenerator_new & cg;
+		LineEnder( CodeGenerator_new & cg ) : cg( cg ) {}
+		std::ostream & operator()( std::ostream & ) const;
+	};
+	friend std::ostream & operator<<( std::ostream & os, const LineEnder & e ) {
+		return e( os );
+	}
+
+	/// Wrapper class to help print vectors of Labels.
+	struct LabelPrinter {
+		LabelPrinter( CodeGenerator_new & cg ) : cg( cg ), labels( nullptr ) {}
+		LabelPrinter & operator()( std::vector<ast::Label> const & l );
+		std::ostream & operator()( std::ostream & ) const;
+		CodeGenerator_new & cg;
+		std::vector<ast::Label> const * labels;
+	};
+	friend std::ostream & operator<<( std::ostream & os, const LabelPrinter & p ) {
+		return p( os );
+	}
+
+	static int tabsize;
+
+	Indenter indent;
+	std::ostream & output;
+	Options options;
+	LabelPrinter printLabels;
+
+	CodeLocation currentLocation;
+	void updateLocation( CodeLocation const & to );
+
+	template<typename Iterator>
+	void genCommaList( Iterator begin, Iterator end ) {
+		if ( begin == end ) return;
+		while (true) {
+			(*begin++)->accept( *visitor );
+			if ( begin == end ) break;
+			output << ", ";
+		}
+	}
+
+public:
+	LineEnder endl;
+	void updateLocation( ast::ParseNode const * to );
+
+	template<typename T>
+	void genCommaList( std::vector<ast::ptr<T>> const & range ) {
+		genCommaList( range.begin(), range.end() );
+	}
+
+	void genAttributes( std::vector<ast::ptr<ast::Attribute>> const & );
+
+private:
+	void asmName( ast::DeclWithType const * decl );
+	void extension( ast::Decl const * );
+	void extension( ast::Expr const * );
+
+	void handleStorageClass( ast::DeclWithType const * decl );
+	void handleAggregate( ast::AggregateDecl const *, const std::string & );
+	void handleTypedef( ast::NamedTypeDecl const * type );
+	std::string mangleName( ast::DeclWithType const * decl );
+};
+
+inline bool doSemicolon( ast::Decl const * decl ) {
+	if ( auto func = dynamic_cast<ast::FunctionDecl const *>( decl ) ) {
+		return !func->stmts;
+	}
+	return true;
+}
+
+} // namespace CodeGen
Index: src/CodeGen/FixMain.h
===================================================================
--- src/CodeGen/FixMain.h	(revision d22bf87d06423658d00bdc0bc13351ccfbc2adba)
+++ src/CodeGen/FixMain.h	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -20,4 +20,5 @@
 #include <list>
 
+#include "AST/LinkageSpec.hpp"
 #include "SynTree/LinkageSpec.h"
 
@@ -34,4 +35,7 @@
 	static inline LinkageSpec::Spec mainLinkage() {
 		return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;
+	}
+	static inline ast::Linkage::Spec getMainLinkage() {
+		return replace_main ? ast::Linkage::Cforall : ast::Linkage::C;
 	}
 
Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision d22bf87d06423658d00bdc0bc13351ccfbc2adba)
+++ src/CodeGen/GenType.cc	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -19,5 +19,8 @@
 #include <sstream>                // for operator<<, ostringstream, basic_os...
 
+#include "AST/Print.hpp"          // for print
+#include "AST/Vector.hpp"         // for vector
 #include "CodeGenerator.h"        // for CodeGenerator
+#include "CodeGeneratorNew.hpp"   // for CodeGenerator_new
 #include "SynTree/Declaration.h"  // for DeclarationWithType
 #include "SynTree/Expression.h"   // for Expression
@@ -352,4 +355,335 @@
 		} // if
 	}
+
+namespace {
+
+#warning Remove the _new when old version is removed.
+struct GenType_new :
+		public ast::WithShortCircuiting,
+		public ast::WithVisitorRef<GenType_new> {
+	std::string result;
+	GenType_new( const std::string &typeString, const Options &options );
+
+	void previsit( ast::Node const * );
+	void postvisit( ast::Node const * );
+
+	void postvisit( ast::FunctionType const * type );
+	void postvisit( ast::VoidType const * type );
+	void postvisit( ast::BasicType const * type );
+	void postvisit( ast::PointerType const * type );
+	void postvisit( ast::ArrayType const * type );
+	void postvisit( ast::ReferenceType const * type );
+	void postvisit( ast::StructInstType const * type );
+	void postvisit( ast::UnionInstType const * type );
+	void postvisit( ast::EnumInstType const * type );
+	void postvisit( ast::TypeInstType const * type );
+	void postvisit( ast::TupleType const * type );
+	void postvisit( ast::VarArgsType const * type );
+	void postvisit( ast::ZeroType const * type );
+	void postvisit( ast::OneType const * type );
+	void postvisit( ast::GlobalScopeType const * type );
+	void postvisit( ast::TraitInstType const * type );
+	void postvisit( ast::TypeofType const * type );
+	void postvisit( ast::VTableType const * type );
+	void postvisit( ast::QualifiedType const * type );
+
+private:
+	void handleQualifiers( ast::Type const *type );
+	std::string handleGeneric( ast::BaseInstType const * type );
+	void genArray( const ast::CV::Qualifiers &qualifiers, ast::Type const *base, ast::Expr const *dimension, bool isVarLen, bool isStatic );
+	std::string genParamList( const ast::vector<ast::Type> & );
+
+	Options options;
+};
+
+GenType_new::GenType_new( const std::string &typeString, const Options &options ) : result( typeString ), options( options ) {}
+
+void GenType_new::previsit( ast::Node const * ) {
+	// Turn off automatic recursion for all nodes, to allow each visitor to
+	// precisely control the order in which its children are visited.
+	visit_children = false;
+}
+
+void GenType_new::postvisit( ast::Node const * node ) {
+	std::stringstream ss;
+	ast::print( ss, node );
+	assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
+}
+
+void GenType_new::postvisit( ast::VoidType const * type ) {
+	result = "void " + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::BasicType const * type ) {
+	ast::BasicType::Kind kind = type->kind;
+	assert( 0 <= kind && kind < ast::BasicType::NUMBER_OF_BASIC_TYPES );
+	result = std::string( ast::BasicType::typeNames[kind] ) + " " + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::genArray( const ast::CV::Qualifiers & qualifiers, ast::Type const * base, ast::Expr const *dimension, bool isVarLen, bool isStatic ) {
+	std::ostringstream os;
+	if ( result != "" ) {
+		if ( result[ 0 ] == '*' ) {
+			os << "(" << result << ")";
+		} else {
+			os << result;
+		}
+	}
+	os << "[";
+	if ( isStatic ) {
+		os << "static ";
+	}
+	if ( qualifiers.is_const ) {
+		os << "const ";
+	}
+	if ( qualifiers.is_volatile ) {
+		os << "volatile ";
+	}
+	if ( qualifiers.is_restrict ) {
+		os << "__restrict ";
+	}
+	if ( qualifiers.is_atomic ) {
+		os << "_Atomic ";
+	}
+	if ( dimension != 0 ) {
+		ast::Pass<CodeGenerator_new>::read( dimension, os, options );
+	} else if ( isVarLen ) {
+		// no dimension expression on a VLA means it came in with the * token
+		os << "*";
+	}
+	os << "]";
+
+	result = os.str();
+
+	base->accept( *visitor );
+}
+
+void GenType_new::postvisit( ast::PointerType const * type ) {
+	if ( type->isStatic || type->isVarLen || type->dimension ) {
+		genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
+	} else {
+		handleQualifiers( type );
+		if ( result[ 0 ] == '?' ) {
+			result = "* " + result;
+		} else {
+			result = "*" + result;
+		}
+		type->base->accept( *visitor );
+	}
+}
+
+void GenType_new::postvisit( ast::ArrayType const * type ) {
+	genArray( type->qualifiers, type->base, type->dimension, type->isVarLen, type->isStatic );
+}
+
+void GenType_new::postvisit( ast::ReferenceType const * type ) {
+	assertf( !options.genC, "Reference types should not reach code generation." );
+	handleQualifiers( type );
+	result = "&" + result;
+	type->base->accept( *visitor );
+}
+
+void GenType_new::postvisit( ast::FunctionType const * type ) {
+	std::ostringstream os;
+
+	if ( result != "" ) {
+		if ( result[ 0 ] == '*' ) {
+			os << "(" << result << ")";
+		} else {
+			os << result;
+		}
+	}
+
+	if ( type->params.empty() ) {
+		if ( type->isVarArgs ) {
+			os << "()";
+		} else {
+			os << "(void)";
+		}
+	} else {
+		os << "(" ;
+
+		os << genParamList( type->params );
+
+		if ( type->isVarArgs ) {
+			os << ", ...";
+		}
+		os << ")";
+	}
+
+	result = os.str();
+
+	if ( type->returns.size() == 0 ) {
+		result = "void " + result;
+	} else {
+		type->returns.front()->accept( *visitor );
+	}
+
+	// Add forall clause.
+	if( !type->forall.empty() && !options.genC ) {
+		//assertf( !options.genC, "FunctionDecl type parameters should not reach code generation." );
+		std::ostringstream os;
+		ast::Pass<CodeGenerator_new> cg( os, options );
+		os << "forall(";
+		cg.core.genCommaList( type->forall );
+		os << ")" << std::endl;
+		result = os.str() + result;
+	}
+}
+
+std::string GenType_new::handleGeneric( ast::BaseInstType const * type ) {
+	if ( !type->params.empty() ) {
+		std::ostringstream os;
+		ast::Pass<CodeGenerator_new> cg( os, options );
+		os << "(";
+		cg.core.genCommaList( type->params );
+		os << ") ";
+		return os.str();
+	}
+	return "";
+}
+
+void GenType_new::postvisit( ast::StructInstType const * type )  {
+	result = type->name + handleGeneric( type ) + " " + result;
+	if ( options.genC ) result = "struct " + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::UnionInstType const * type ) {
+	result = type->name + handleGeneric( type ) + " " + result;
+	if ( options.genC ) result = "union " + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::EnumInstType const * type ) {
+	if ( type->base && type->base->base ) {
+		result = genType( type->base->base, result, options );
+	} else {
+		result = type->name + " " + result;
+		if ( options.genC ) {
+			result = "enum " + result;
+		}
+	}
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::TypeInstType const * type ) {
+	assertf( !options.genC, "TypeInstType should not reach code generation." );
+	result = type->name + " " + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::TupleType const * type ) {
+	assertf( !options.genC, "TupleType should not reach code generation." );
+	unsigned int i = 0;
+	std::ostringstream os;
+	os << "[";
+	for ( ast::ptr<ast::Type> const & t : type->types ) {
+		i++;
+		os << genType( t, "", options ) << (i == type->size() ? "" : ", ");
+	}
+	os << "] ";
+	result = os.str() + result;
+}
+
+void GenType_new::postvisit( ast::VarArgsType const * type ) {
+	result = "__builtin_va_list " + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::ZeroType const * type ) {
+	// Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
+	result = (options.pretty ? "zero_t " : "long int ") + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::OneType const * type ) {
+	// Ideally these wouldn't hit codegen at all, but should be safe to make them ints.
+	result = (options.pretty ? "one_t " : "long int ") + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::GlobalScopeType const * type ) {
+	assertf( !options.genC, "GlobalScopeType should not reach code generation." );
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::TraitInstType const * type ) {
+	assertf( !options.genC, "TraitInstType should not reach code generation." );
+	result = type->name + " " + result;
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::TypeofType const * type ) {
+	std::ostringstream os;
+	os << "typeof(";
+	ast::Pass<CodeGenerator_new>::read( type, os, options );
+	os << ") " << result;
+	result = os.str();
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::VTableType const * type ) {
+	assertf( !options.genC, "Virtual table types should not reach code generation." );
+	std::ostringstream os;
+	os << "vtable(" << genType( type->base, "", options ) << ") " << result;
+	result = os.str();
+	handleQualifiers( type );
+}
+
+void GenType_new::postvisit( ast::QualifiedType const * type ) {
+	assertf( !options.genC, "QualifiedType should not reach code generation." );
+	std::ostringstream os;
+	os << genType( type->parent, "", options ) << "." << genType( type->child, "", options ) << result;
+	result = os.str();
+	handleQualifiers( type );
+}
+
+void GenType_new::handleQualifiers( ast::Type const * type ) {
+	if ( type->is_const() ) {
+		result = "const " + result;
+	}
+	if ( type->is_volatile() ) {
+		result = "volatile " + result;
+	}
+	if ( type->is_restrict() ) {
+		result = "__restrict " + result;
+	}
+	if ( type->is_atomic() ) {
+		result = "_Atomic " + result;
+	}
+}
+
+std::string GenType_new::genParamList( const ast::vector<ast::Type> & range ) {
+	auto cur = range.begin();
+	auto end = range.end();
+	if ( cur == end ) return "";
+	std::ostringstream oss;
+	for ( unsigned int i = 0 ; ; ++i ) {
+		oss << genType( *cur++, "__param_" + std::to_string(i), options );
+		if ( cur == end ) break;
+		oss << ", ";
+	}
+	return oss.str();
+}
+
+} // namespace
+
+std::string genType( ast::Type const * type, const std::string & base, const Options & options ) {
+	std::ostringstream os;
+	if ( !type->attributes.empty() ) {
+		ast::Pass<CodeGenerator_new> cg( os, options );
+		cg.core.genAttributes( type->attributes );
+	}
+
+	return os.str() + ast::Pass<GenType_new>::read( type, base, options );
+}
+
+std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options ) {
+	return ast::Pass<GenType_new>::read( type, base, options );
+}
+
 } // namespace CodeGen
 
Index: src/CodeGen/GenType.h
===================================================================
--- src/CodeGen/GenType.h	(revision d22bf87d06423658d00bdc0bc13351ccfbc2adba)
+++ src/CodeGen/GenType.h	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -21,4 +21,7 @@
 
 class Type;
+namespace ast {
+	class Type;
+}
 
 namespace CodeGen {
@@ -26,4 +29,8 @@
 	std::string genType( Type *type, const std::string &baseString, bool pretty = false, bool genC = false, bool lineMarks = false );
 	std::string genPrettyType( Type * type, const std::string & baseString );
+
+std::string genType( ast::Type const * type, const std::string & base, const Options & options );
+std::string genTypeNoAttr( ast::Type const * type, const std::string & base, const Options & options );
+
 } // namespace CodeGen
 
Index: src/CodeGen/Generate.cc
===================================================================
--- src/CodeGen/Generate.cc	(revision d22bf87d06423658d00bdc0bc13351ccfbc2adba)
+++ src/CodeGen/Generate.cc	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -19,4 +19,5 @@
 #include <string>                    // for operator<<
 
+#include "CodeGeneratorNew.hpp"      // for CodeGenerator_new, doSemicolon, ...
 #include "CodeGenerator.h"           // for CodeGenerator, doSemicolon, oper...
 #include "GenType.h"                 // for genPrettyType
@@ -93,4 +94,46 @@
 		}
 	} // namespace
+
+namespace {
+	bool shouldClean( ast::Decl const * decl ) {
+		return dynamic_cast<ast::TraitDecl const *>( decl );
+	}
+
+	/// Removes various nodes that should not exist in CodeGen.
+	struct TreeCleaner_new {
+		ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt ) {
+			auto mutStmt = ast::mutate( stmt );
+			erase_if( mutStmt->kids, []( ast::Stmt const * stmt ){
+				auto declStmt = dynamic_cast<ast::DeclStmt const *>( stmt );
+				return ( declStmt ) ? shouldClean( declStmt->decl ) : false;
+			} );
+			return mutStmt;
+		}
+
+		ast::Stmt const * postvisit( ast::ImplicitCtorDtorStmt const * stmt ) {
+			return stmt->callStmt;
+		}
+	};
+} // namespace
+
+void generate( ast::TranslationUnit & translationUnit, std::ostream & os, bool doIntrinsics,
+		bool pretty, bool generateC, bool lineMarks, bool printExprTypes ) {
+	erase_if( translationUnit.decls, shouldClean );
+	ast::Pass<TreeCleaner_new>::run( translationUnit );
+
+	ast::Pass<CodeGenerator_new> cgv( os,
+			Options( pretty, generateC, lineMarks, printExprTypes ) );
+	for ( auto & decl : translationUnit.decls ) {
+		if ( decl->linkage.is_generatable && (doIntrinsics || !decl->linkage.is_builtin ) ) {
+			cgv.core.updateLocation( decl );
+			decl->accept( cgv );
+			if ( doSemicolon( decl ) ) {
+				os << ";";
+			}
+			os << cgv.core.endl;
+		}
+	}
+}
+
 } // namespace CodeGen
 
Index: src/CodeGen/Generate.h
===================================================================
--- src/CodeGen/Generate.h	(revision d22bf87d06423658d00bdc0bc13351ccfbc2adba)
+++ src/CodeGen/Generate.h	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -22,4 +22,8 @@
 class Declaration;
 
+namespace ast {
+	class TranslationUnit;
+}
+
 namespace CodeGen {
 	/// Generates code. doIntrinsics determines if intrinsic functions are printed, pretty formats output nicely (e.g., uses unmangled names, etc.), generateC is true when the output must consist only of C code (allows some assertions, etc.)
@@ -28,4 +32,14 @@
 	/// Generate code for a single node -- helpful for debugging in gdb
 	void generate( BaseSyntaxNode * node, std::ostream & os );
+
+/// Generates all code in transUnit and writing it to the os.
+/// doIntrinsics: Should intrinsic functions be printed?
+/// pretty: Format output nicely (e.g., uses unmangled names, etc.).
+/// generateC: Make sure the output only consists of C code (allows some assertions, etc.)
+/// lineMarks: Output line marks (processed line directives) in the output.
+/// printExprTypes: Print the types of expressions in comments.
+void generate( ast::TranslationUnit & transUnit, std::ostream &os, bool doIntrinsics,
+		bool pretty, bool generateC, bool lineMarks, bool printExprTypes );
+
 } // namespace CodeGen
 
Index: src/CodeGen/module.mk
===================================================================
--- src/CodeGen/module.mk	(revision d22bf87d06423658d00bdc0bc13351ccfbc2adba)
+++ src/CodeGen/module.mk	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -24,4 +24,6 @@
 	CodeGen/CodeGenerator.cc \
 	CodeGen/CodeGenerator.h \
+	CodeGen/CodeGeneratorNew.cpp \
+	CodeGen/CodeGeneratorNew.hpp \
 	CodeGen/Generate.cc \
 	CodeGen/Generate.h \
Index: src/main.cc
===================================================================
--- src/main.cc	(revision d22bf87d06423658d00bdc0bc13351ccfbc2adba)
+++ src/main.cc	(revision 8941b6ba42567534f65c1e322eb782a5984d80f5)
@@ -427,9 +427,7 @@
 		PASS( "Link-Once", CodeGen::translateLinkOnce, transUnit );
 
-		translationUnit = convert( std::move( transUnit ) );
-
 		// Code has been lowered to C, now we can start generation.
 
-		DUMP( bcodegenp, translationUnit );
+		DUMP( bcodegenp, std::move( transUnit ) );
 
 		if ( optind < argc ) {							// any commands after the flags and input file ? => output file name
@@ -437,6 +435,7 @@
 		} // if
 
-		CodeTools::fillLocations( translationUnit );
-		PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
+		PASS( "Code Gen", CodeGen::generate, transUnit, *output, !genproto, prettycodegenp, true, linemarks, false );
+
+		translationUnit = convert( std::move( transUnit ) );
 
 		CodeGen::FixMain::fix( translationUnit, *output,
