Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,1030 +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.
-//
-// DeclarationNode.cc --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Sat May 16 12:34:05 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Feb 23 18:25:57 2024
-// Update Count     : 1533
-//
-
-#include "DeclarationNode.h"
-
-#include <cassert>                 // for assert, assertf, strict_dynamic_cast
-#include <iterator>                // for back_insert_iterator
-#include <list>                    // for list
-#include <memory>                  // for unique_ptr
-#include <ostream>                 // for operator<<, ostream, basic_ostream
-#include <string>                  // for string, operator+, allocator, char...
-
-#include "AST/Attribute.hpp"       // for Attribute
-#include "AST/Copy.hpp"            // for shallowCopy
-#include "AST/Decl.hpp"            // for Decl
-#include "AST/Expr.hpp"            // for Expr
-#include "AST/Print.hpp"           // for print
-#include "AST/Stmt.hpp"            // for AsmStmt, DirectiveStmt
-#include "AST/StorageClasses.hpp"  // for Storage::Class
-#include "AST/Type.hpp"            // for Type
-#include "Common/CodeLocation.h"   // for CodeLocation
-#include "Common/Iterate.hpp"      // for reverseIterate
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/UniqueName.h"     // for UniqueName
-#include "Common/utility.h"        // for copy, spliceBegin
-#include "Parser/ExpressionNode.h" // for ExpressionNode
-#include "Parser/InitializerNode.h"// for InitializerNode
-#include "Parser/StatementNode.h"  // for StatementNode
-#include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
-#include "TypedefTable.h"          // for TypedefTable
-
-extern TypedefTable typedefTable;
-
-using namespace std;
-
-UniqueName DeclarationNode::anonymous( "__anonymous" );
-
-extern ast::Linkage::Spec linkage;						// defined in parser.yy
-
-DeclarationNode::DeclarationNode() :
-	linkage( ::linkage ) {
-
-	variable.tyClass = ast::TypeDecl::NUMBER_OF_KINDS;
-	variable.assertions = nullptr;
-	variable.initializer = nullptr;
-
-	assert.condition = nullptr;
-	assert.message = nullptr;
-}
-
-DeclarationNode::~DeclarationNode() {
-	delete name;
-
-	delete variable.assertions;
-	delete variable.initializer;
-
-	delete type;
-	delete bitfieldWidth;
-
-	delete asmStmt;
-	// asmName, no delete, passed to next stage
-	delete initializer;
-
-	delete assert.condition;
-	delete assert.message;
-}
-
-DeclarationNode * DeclarationNode::clone() const {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->next = maybeCopy( next );
-	newnode->name = name ? new string( *name ) : nullptr;
-
-	newnode->type = maybeCopy( type );
-	newnode->inLine = inLine;
-	newnode->storageClasses = storageClasses;
-	newnode->funcSpecs = funcSpecs;
-	newnode->bitfieldWidth = maybeCopy( bitfieldWidth );
-	newnode->enumeratorValue.reset( maybeCopy( enumeratorValue.get() ) );
-	newnode->hasEllipsis = hasEllipsis;
-	newnode->linkage = linkage;
-	newnode->asmName = maybeCopy( asmName );
-	newnode->attributes = attributes;
-	newnode->initializer = maybeCopy( initializer );
-	newnode->extension = extension;
-	newnode->asmStmt = maybeCopy( asmStmt );
-	newnode->error = error;
-
-	newnode->variable.tyClass = variable.tyClass;
-	newnode->variable.assertions = maybeCopy( variable.assertions );
-	newnode->variable.initializer = maybeCopy( variable.initializer );
-
-	newnode->assert.condition = maybeCopy( assert.condition );
-	newnode->assert.message = maybeCopy( assert.message );
-	return newnode;
-} // DeclarationNode::clone
-
-void DeclarationNode::print( std::ostream & os, int indent ) const {
-	os << string( indent, ' ' );
-	if ( name ) {
-		os << *name << ": ";
-	} // if
-
-	if ( linkage != ast::Linkage::Cforall ) {
-		os << ast::Linkage::name( linkage ) << " ";
-	} // if
-
-	ast::print( os, storageClasses );
-	ast::print( os, funcSpecs );
-
-	if ( type ) {
-		type->print( os, indent );
-	} else {
-		os << "untyped entity ";
-	} // if
-
-	if ( bitfieldWidth ) {
-		os << endl << string( indent + 2, ' ' ) << "with bitfield width ";
-		bitfieldWidth->printOneLine( os );
-	} // if
-
-	if ( initializer ) {
-		os << endl << string( indent + 2, ' ' ) << "with initializer ";
-		initializer->printOneLine( os );
-		os << " maybe constructed? " << initializer->get_maybeConstructed();
-	} // if
-
-	if ( ! attributes.empty() ) {
-		os << string( indent + 2, ' ' ) << "with attributes" << endl;
-		for ( ast::ptr<ast::Attribute> const & attr : reverseIterate( attributes ) ) {
-			os << string( indent + 4, ' ' );
-			ast::print( os, attr, indent + 2 );
-		} // for
-	} // if
-
-	os << endl;
-}
-
-void DeclarationNode::printList( std::ostream & os, int indent ) const {
-	ParseList::printList( os, indent );
-	if ( hasEllipsis ) {
-		os << string( indent, ' ' )  << "and a variable number of other arguments" << endl;
-	} // if
-}
-
-DeclarationNode * DeclarationNode::newFromTypeData( TypeData * type ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = type;
-	return newnode;
-} // DeclarationNode::newFromTypeData
-
-DeclarationNode * DeclarationNode::newStorageClass( ast::Storage::Classes sc ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->storageClasses = sc;
-	return newnode;
-} // DeclarationNode::newStorageClass
-
-DeclarationNode * DeclarationNode::newFuncSpecifier( ast::Function::Specs fs ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->funcSpecs = fs;
-	return newnode;
-} // DeclarationNode::newFuncSpecifier
-
-DeclarationNode * DeclarationNode::newAggregate( ast::AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = new TypeData( TypeData::Aggregate );
-	newnode->type->aggregate.kind = kind;
-	newnode->type->aggregate.anon = name == nullptr;
-	newnode->type->aggregate.name = newnode->type->aggregate.anon ? new string( DeclarationNode::anonymous.newName() ) : name;
-	newnode->type->aggregate.actuals = actuals;
-	newnode->type->aggregate.fields = fields;
-	newnode->type->aggregate.body = body;
-	return newnode;
-} // DeclarationNode::newAggregate
-
-DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body, bool typed, DeclarationNode * base, EnumHiding hiding ) {
-	DeclarationNode * newnode = newAggregate( ast::AggregateDecl::Enum, name, nullptr, constants, body );
-	newnode->type->aggregate.typed = typed;
-	newnode->type->aggregate.hiding = hiding;
-	if ( base ) {
-		assert( typed );
-		assert( base->type );
-		newnode->type->base = base->type;
-		base->type = nullptr;
-		delete base;
-	} // if
-
-	return newnode;
-} // DeclarationNode::newEnum
-
-DeclarationNode * DeclarationNode::newName( const string * name ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	assert( ! newnode->name );
-	newnode->name = name;
-	return newnode;
-} // DeclarationNode::newName
-
-DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) {
-	DeclarationNode * newnode = newName( name );
-	newnode->enumeratorValue.reset( constant );
-	return newnode;
-} // DeclarationNode::newEnumConstant
-
-DeclarationNode * DeclarationNode::newEnumValueGeneric( const string * name, InitializerNode * init ) {
-	if ( nullptr == init ) {
-		return newName( name );
-	} else if ( init->get_expression() ) {
-		return newEnumConstant( name, init->get_expression() );
-	} else {
-		DeclarationNode * newnode = newName( name );
-		newnode->initializer = init;
-		return newnode;
-	} // if
-} // DeclarationNode::newEnumValueGeneric
-
-DeclarationNode * DeclarationNode::newEnumInLine( const std::string * name ) {
-	DeclarationNode * newnode = newName( name );
-	newnode->enumInLine = true;
-	return newnode;
-}
-
-DeclarationNode * DeclarationNode::newTypeParam( ast::TypeDecl::Kind tc, const string * name ) {
-	DeclarationNode * newnode = newName( name );
-	newnode->type = nullptr;
-	newnode->variable.tyClass = tc;
-	newnode->variable.assertions = nullptr;
-	return newnode;
-} // DeclarationNode::newTypeParam
-
-DeclarationNode * DeclarationNode::newTrait( const string * name, DeclarationNode * params, DeclarationNode * asserts ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = new TypeData( TypeData::Aggregate );
-	newnode->type->aggregate.name = name;
-	newnode->type->aggregate.kind = ast::AggregateDecl::Trait;
-	newnode->type->aggregate.params = params;
-	newnode->type->aggregate.fields = asserts;
-	return newnode;
-} // DeclarationNode::newTrait
-
-DeclarationNode * DeclarationNode::newTraitUse( const string * name, ExpressionNode * params ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = new TypeData( TypeData::AggregateInst );
-	newnode->type->aggInst.aggregate = new TypeData( TypeData::Aggregate );
-	newnode->type->aggInst.aggregate->aggregate.kind = ast::AggregateDecl::Trait;
-	newnode->type->aggInst.aggregate->aggregate.name = name;
-	newnode->type->aggInst.params = params;
-	return newnode;
-} // DeclarationNode::newTraitUse
-
-DeclarationNode * DeclarationNode::newTypeDecl( const string * name, DeclarationNode * typeParams ) {
-	DeclarationNode * newnode = newName( name );
-	newnode->type = new TypeData( TypeData::Symbolic );
-	newnode->type->symbolic.isTypedef = false;
-	newnode->type->symbolic.params = typeParams;
-	return newnode;
-} // DeclarationNode::newTypeDecl
-
-DeclarationNode * DeclarationNode::newPointer( DeclarationNode * qualifiers, OperKinds kind ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = new TypeData( kind == OperKinds::PointTo ? TypeData::Pointer : TypeData::Reference );
-	if ( kind == OperKinds::And ) {
-		// T && is parsed as 'And' operator rather than two references => add a second reference type
-		TypeData * td = new TypeData( TypeData::Reference );
-		td->base = newnode->type;
-		newnode->type = td;
-	}
-	if ( qualifiers ) {
-		return newnode->addQualifiers( qualifiers );
-	} else {
-		return newnode;
-	} // if
-} // DeclarationNode::newPointer
-
-DeclarationNode * DeclarationNode::newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = new TypeData( TypeData::Array );
-	newnode->type->array.dimension = size;
-	newnode->type->array.isStatic = isStatic;
-	newnode->type->array.isVarLen = size && !size->isExpressionType<ast::ConstantExpr *>();
-	return newnode->addQualifiers( qualifiers );
-} // DeclarationNode::newArray
-
-DeclarationNode * DeclarationNode::newVarArray( DeclarationNode * qualifiers ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = new TypeData( TypeData::Array );
-	newnode->type->array.dimension = nullptr;
-	newnode->type->array.isStatic = false;
-	newnode->type->array.isVarLen = true;
-	return newnode->addQualifiers( qualifiers );
-}
-
-DeclarationNode * DeclarationNode::newBitfield( ExpressionNode * size ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->bitfieldWidth = size;
-	return newnode;
-}
-
-DeclarationNode * DeclarationNode::newTuple( DeclarationNode * members ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = new TypeData( TypeData::Tuple );
-	newnode->type->tuple = members;
-	return newnode;
-}
-
-DeclarationNode * DeclarationNode::newTypeof( ExpressionNode * expr, bool basetypeof ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = new TypeData( basetypeof ? TypeData::Basetypeof : TypeData::Typeof );
-	newnode->type->typeexpr = expr;
-	return newnode;
-}
-
-DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {
-	DeclarationNode * newnode = newName( name );
-	newnode->type = new TypeData( TypeData::Function );
-	newnode->type->function.params = param;
-	newnode->type->function.body = body;
-
-	if ( ret ) {
-		newnode->type->base = ret->type;
-		ret->type = nullptr;
-		delete ret;
-	} // if
-
-	return newnode;
-} // DeclarationNode::newFunction
-
-DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->type = nullptr;
-	std::vector<ast::ptr<ast::Expr>> exprs;
-	buildList( expr, exprs );
-	newnode->attributes.push_back( new ast::Attribute( *name, std::move( exprs ) ) );
-	delete name;
-	return newnode;
-}
-
-DeclarationNode * DeclarationNode::newDirectiveStmt( StatementNode * stmt ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->directiveStmt = stmt;
-	return newnode;
-}
-
-DeclarationNode * DeclarationNode::newAsmStmt( StatementNode * stmt ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->asmStmt = stmt;
-	return newnode;
-}
-
-DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, ast::Expr * message ) {
-	DeclarationNode * newnode = new DeclarationNode;
-	newnode->assert.condition = condition;
-	newnode->assert.message = message;
-	return newnode;
-}
-
-static void appendError( string & dst, const string & src ) {
-	if ( src.empty() ) return;
-	if ( dst.empty() ) { dst = src; return; }
-	dst += ", " + src;
-} // appendError
-
-void DeclarationNode::checkQualifiers( const TypeData * src, const TypeData * dst ) {
-	const ast::CV::Qualifiers qsrc = src->qualifiers, qdst = dst->qualifiers; // optimization
-	const ast::CV::Qualifiers duplicates = qsrc & qdst;
-
-	if ( duplicates.any() ) {
-		std::stringstream str;
-		str << "duplicate ";
-		ast::print( str, duplicates );
-		str << "qualifier(s)";
-		appendError( error, str.str() );
-	} // for
-} // DeclarationNode::checkQualifiers
-
-void DeclarationNode::checkSpecifiers( DeclarationNode * src ) {
-	ast::Function::Specs fsDups = funcSpecs & src->funcSpecs;
-	if ( fsDups.any() ) {
-		std::stringstream str;
-		str << "duplicate ";
-		ast::print( str, fsDups );
-		str << "function specifier(s)";
-		appendError( error, str.str() );
-	} // if
-
-	// Skip if everything is unset.
-	if ( storageClasses.any() && src->storageClasses.any() ) {
-		ast::Storage::Classes dups = storageClasses & src->storageClasses;
-		// Check for duplicates.
-		if ( dups.any() ) {
-			std::stringstream str;
-			str << "duplicate ";
-			ast::print( str, dups );
-			str << "storage class(es)";
-			appendError( error, str.str() );
-		// Check for conflicts.
-		} else if ( !src->storageClasses.is_threadlocal_any() ) {
-			std::stringstream str;
-			str << "conflicting ";
-			ast::print( str, ast::Storage::Classes( 1 << storageClasses.ffs() ) );
-			str << "& ";
-			ast::print( str, ast::Storage::Classes( 1 << src->storageClasses.ffs() ) );
-			str << "storage classes";
-			appendError( error, str.str() );
-			// FIX to preserve invariant of one basic storage specifier
-			src->storageClasses.reset();
-		}
-	} // if
-
-	appendError( error, src->error );
-} // DeclarationNode::checkSpecifiers
-
-DeclarationNode * DeclarationNode::copySpecifiers( DeclarationNode * q, bool copyattr ) {
-	funcSpecs |= q->funcSpecs;
-	storageClasses |= q->storageClasses;
-
-	if ( copyattr ) {
-		std::vector<ast::ptr<ast::Attribute>> tmp;
-		tmp.reserve( q->attributes.size() );
-		for ( auto const & attr : q->attributes ) {
-			tmp.emplace_back( ast::shallowCopy( attr.get() ) );
-		} // for
-		spliceBegin( attributes, tmp );
-	} // if
-
-	return this;
-} // DeclarationNode::copySpecifiers
-
-DeclarationNode * DeclarationNode::addQualifiers( DeclarationNode * q ) {
-	if ( ! q ) { return this; }							// empty qualifier
-
-	checkSpecifiers( q );
-	copySpecifiers( q );
-
-	if ( ! q->type ) { delete q; return this; }
-
-	if ( ! type ) {
-		type = q->type;									// reuse structure
-		q->type = nullptr;
-		delete q;
-		return this;
-	} // if
-
-	checkQualifiers( type, q->type );
-	TypeData::BuiltinType const builtin = type->builtintype;
-	if ( (builtin == TypeData::Zero || builtin == TypeData::One) && q->type->qualifiers.any() && error.length() == 0 ) {
-		SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, TypeData::builtinTypeNames[builtin] );
-	} // if
-	type = ::addQualifiers( type, q->type );
-	q->type = nullptr;
-
-	delete q;
-	return this;
-} // addQualifiers
-
-DeclarationNode * DeclarationNode::addType( DeclarationNode * o, bool copyattr ) {
-	if ( !o ) return this;
-
-	checkSpecifiers( o );
-	copySpecifiers( o, copyattr );
-	if ( o->type ) {
-		type = ::addType( type, o->type, o->attributes );
-		o->type = nullptr;
-	} // if
-	if ( o->bitfieldWidth ) {
-		bitfieldWidth = o->bitfieldWidth;
-	} // if
-
-	// there may be typedefs chained onto the type
-	if ( o->next ) {
-		set_last( o->next->clone() );
-	} // if
-
-	delete o;
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addEnumBase( DeclarationNode * o ) {
-	if ( o && o->type ) {
-		type->base = o->type;
-	} // if
-	delete o;
-	return this;
-}
-
-// This code handles a special issue with the attribute transparent_union.
-//
-//    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
-//
-// Here the attribute aligned goes with the typedef_name, so variables declared of this type are
-// aligned.  However, the attribute transparent_union must be moved from the typedef_name to
-// alias union U.  Currently, this is the only know attribute that must be moved from typedef to
-// alias.
-static void moveUnionAttribute( DeclarationNode * decl, DeclarationNode * unionDecl ) {
-	assert( decl->type->kind == TypeData::Symbolic );
-	assert( decl->type->symbolic.isTypedef );
-	assert( unionDecl->type->kind == TypeData::Aggregate );
-
-	if ( unionDecl->type->aggregate.kind != ast::AggregateDecl::Union ) return;
-
-	// Ignore the Aggregate_t::attributes. Why did we add that before the rework?
-	for ( auto attr = decl->attributes.begin() ; attr != decl->attributes.end() ; ) {
-		if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
-			unionDecl->attributes.emplace_back( attr->release() );
-			attr = decl->attributes.erase( attr );
-		} else {
-			++attr;
-		}
-	}
-}
-
-// Helper for addTypedef, handles the case where the typedef wraps an
-// aggregate declaration (not a type), returns a chain of nodes.
-static DeclarationNode * addTypedefAggr(
-		DeclarationNode * olddecl, TypeData * newtype ) {
-	TypeData *& oldaggr = olddecl->type->aggInst.aggregate;
-
-	// Handle anonymous aggregates: typedef struct { int i; } foo
-	// Give the typedefed type a consistent name across translation units.
-	if ( oldaggr->aggregate.anon ) {
-		delete oldaggr->aggregate.name;
-		oldaggr->aggregate.name = new string( "__anonymous_" + *olddecl->name );
-		oldaggr->aggregate.anon = false;
-		oldaggr->qualifiers.reset();
-	}
-
-	// Replace the wrapped TypeData with a forward declaration.
-	TypeData * newaggr = new TypeData( TypeData::Aggregate );
-	newaggr->aggregate.kind = oldaggr->aggregate.kind;
-	newaggr->aggregate.name = oldaggr->aggregate.name ? new string( *oldaggr->aggregate.name ) : nullptr;
-	newaggr->aggregate.body = false;
-	newaggr->aggregate.anon = oldaggr->aggregate.anon;
-	newaggr->aggregate.typed = oldaggr->aggregate.typed;
-	newaggr->aggregate.hiding = oldaggr->aggregate.hiding;
-	swap( newaggr, oldaggr );
-
-	newtype->base = olddecl->type;
-	olddecl->type = newtype;
-	DeclarationNode * newdecl = new DeclarationNode;
-	newdecl->type = newaggr;
-	newdecl->next = olddecl;
-
-	moveUnionAttribute( olddecl, newdecl );
-
-	return newdecl;
-}
-
-// Wrap the declaration in a typedef. It actually does that by modifying the
-// existing declaration, and may split it into two declarations.
-// This only happens if the wrapped type is actually a declaration of a SUE
-// type. If it does, the DeclarationNode for the SUE declaration is the node
-// returned, make sure later transformations are applied to the right node.
-DeclarationNode * DeclarationNode::addTypedef() {
-	TypeData * newtype = new TypeData( TypeData::Symbolic );
-	newtype->symbolic.params = nullptr;
-	newtype->symbolic.isTypedef = true;
-	newtype->symbolic.name = name ? new string( *name ) : nullptr;
-	// If this typedef is wrapping an aggregate, separate them out.
-	if ( TypeData::AggregateInst == type->kind
-			&& TypeData::Aggregate == type->aggInst.aggregate->kind
-			&& type->aggInst.aggregate->aggregate.body ) {
-		return addTypedefAggr( this, newtype );
-	// There is no internal declaration, just a type.
-	} else {
-		newtype->base = type;
-		type = newtype;
-		return this;
-	}
-}
-
-DeclarationNode * DeclarationNode::addAssertions( DeclarationNode * assertions ) {
-	if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
-		extend( variable.assertions, assertions );
-		return this;
-	} // if
-
-	assert( type );
-	assert( TypeData::Symbolic == type->kind );
-	extend( type->symbolic.assertions, assertions );
-
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addName( string * newname ) {
-	assert( ! name );
-	name = newname;
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addAsmName( DeclarationNode * newname ) {
-	assert( ! asmName );
-	asmName = newname ? newname->asmName : nullptr;
-	return this->addQualifiers( newname );
-}
-
-DeclarationNode * DeclarationNode::addBitfield( ExpressionNode * size ) {
-	bitfieldWidth = size;
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addVarArgs() {
-	assert( type );
-	hasEllipsis = true;
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addFunctionBody( StatementNode * body, ExpressionNode * withExprs ) {
-	assert( type );
-	assert( type->kind == TypeData::Function );
-	assert( ! type->function.body );
-	type->function.body = body;
-	type->function.withExprs = withExprs;
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addOldDeclList( DeclarationNode * list ) {
-	assert( type );
-	assert( type->kind == TypeData::Function );
-	assert( ! type->function.oldDeclList );
-	type->function.oldDeclList = list;
-	return this;
-}
-
-DeclarationNode * DeclarationNode::setBase( TypeData * newType ) {
-	if ( type ) {
-		type->setLastBase( newType );
-	} else {
-		type = newType;
-	} // if
-	return this;
-}
-
-DeclarationNode * DeclarationNode::copyAttribute( DeclarationNode * a ) {
-	if ( a ) {
-		spliceBegin( attributes, a->attributes );
-		a->attributes.clear();
-	} // if
-	return this;
-} // copyAttribute
-
-DeclarationNode * DeclarationNode::addPointer( DeclarationNode * p ) {
-	if ( p ) {
-		assert( p->type->kind == TypeData::Pointer || p->type->kind == TypeData::Reference );
-		setBase( p->type );
-		p->type = nullptr;
-		copyAttribute( p );
-		delete p;
-	} // if
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addArray( DeclarationNode * a ) {
-	if ( a ) {
-		assert( a->type->kind == TypeData::Array );
-		setBase( a->type );
-		a->type = nullptr;
-		copyAttribute( a );
-		delete a;
-	} // if
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addNewPointer( DeclarationNode * p ) {
-	if ( !p ) return this;
-	assert( p->type->kind == TypeData::Pointer || p->type->kind == TypeData::Reference );
-	if ( type ) {
-		p->type->base = makeNewBase( type );
-		type = nullptr;
-	} // if
-	delete this;
-	return p;
-}
-
-DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) {
-	if ( !a ) return this;
-	assert( a->type->kind == TypeData::Array );
-	if ( type ) {
-		a->type->setLastBase( makeNewBase( type ) );
-		type = nullptr;
-	} // if
-	delete this;
-	return a;
-}
-
-DeclarationNode * DeclarationNode::addParamList( DeclarationNode * params ) {
-	TypeData * ftype = new TypeData( TypeData::Function );
-	ftype->function.params = params;
-	setBase( ftype );
-	return this;
-}
-
-static TypeData * addIdListToType( TypeData * type, DeclarationNode * ids ) {
-	if ( type ) {
-		if ( type->kind != TypeData::Function ) {
-			type->base = addIdListToType( type->base, ids );
-		} else {
-			type->function.idList = ids;
-		} // if
-		return type;
-	} else {
-		TypeData * newtype = new TypeData( TypeData::Function );
-		newtype->function.idList = ids;
-		return newtype;
-	} // if
-} // addIdListToType
-
-DeclarationNode * DeclarationNode::addIdList( DeclarationNode * ids ) {
-	type = addIdListToType( type, ids );
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addInitializer( InitializerNode * init ) {
-	initializer = init;
-	return this;
-}
-
-DeclarationNode * DeclarationNode::addTypeInitializer( DeclarationNode * init ) {
-	assertf( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
-	variable.initializer = init;
-	return this;
-}
-
-DeclarationNode * DeclarationNode::cloneType( string * name ) {
-	DeclarationNode * newnode = newName( name );
-	newnode->type = maybeCopy( type );
-	newnode->copySpecifiers( this );
-	return newnode;
-}
-
-DeclarationNode * DeclarationNode::cloneBaseType( DeclarationNode * o, bool copyattr ) {
-	if ( ! o ) return nullptr;
-	o->copySpecifiers( this, copyattr );
-	if ( type ) {
-		o->type = ::cloneBaseType( type, o->type );
-	} // if
-	return o;
-}
-
-DeclarationNode * DeclarationNode::extractAggregate() const {
-	if ( type ) {
-		TypeData * ret = typeextractAggregate( type );
-		if ( ret ) {
-			DeclarationNode * newnode = new DeclarationNode;
-			newnode->type = ret;
-			if ( ret->kind == TypeData::Aggregate ) {
-				newnode->attributes.swap( ret->aggregate.attributes );
-			} // if
-			return newnode;
-		} // if
-	} // if
-	return nullptr;
-}
-
-// Get the non-anonymous name of the instance type of the declaration,
-// if one exists.
-static const std::string * getInstTypeOfName( ast::Decl * decl ) {
-	if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
-		if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) {
-			if ( aggr->name.find("anonymous") == std::string::npos ) {
-				return &aggr->name;
-			}
-		}
-	}
-	return nullptr;
-}
-
-void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList ) {
-	SemanticErrorException errors;
-	std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
-
-	for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
-		try {
-			bool extracted_named = false;
-
-			if ( DeclarationNode * extr = cur->extractAggregate() ) {
-				assert( cur->type );
-
-				if ( ast::Decl * decl = extr->build() ) {
-					*out++ = decl;
-
-					// need to remember the cases where a declaration contains an anonymous aggregate definition
-					assert( extr->type );
-					if ( extr->type->kind == TypeData::Aggregate ) {
-						// typedef struct { int A } B is the only case?
-						extracted_named = ! extr->type->aggregate.anon;
-					} else {
-						extracted_named = true;
-					}
-				} // if
-				delete extr;
-			} // if
-
-			if ( ast::Decl * decl = cur->build() ) {
-				if ( "" == decl->name && !cur->get_inLine() ) {
-					// Don't include anonymous declaration for named aggregates,
-					// but do include them for anonymous aggregates, e.g.:
-					// struct S {
-					//   struct T { int x; }; // no anonymous member
-					//   struct { int y; };   // anonymous member
-					//   struct T;            // anonymous member
-					// };
-					if ( extracted_named ) {
-						continue;
-					}
-
-					if ( auto name = getInstTypeOfName( decl ) ) {
-						// Temporary: warn about anonymous member declarations of named types, since
-						// this conflicts with the syntax for the forward declaration of an anonymous type.
-						SemanticWarning( cur->location, Warning::AggrForwardDecl, name->c_str() );
-					}
-				} // if
-				*out++ = decl;
-			} // if
-		} catch ( SemanticErrorException & e ) {
-			errors.append( e );
-		} // try
-	} // for
-
-	if ( ! errors.isEmpty() ) {
-		throw errors;
-	} // if
-} // buildList
-
-// currently only builds assertions, function parameters, and return values
-void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
-	SemanticErrorException errors;
-	std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
-
-	for ( const DeclarationNode * cur = firstNode; cur; cur = cur->next ) {
-		try {
-			ast::Decl * decl = cur->build();
-			assertf( decl, "buildList: build for ast::DeclWithType." );
-			if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
-				dwt->location = cur->location;
-				*out++ = dwt;
-			} else if ( ast::StructDecl * agg = dynamic_cast<ast::StructDecl *>( decl ) ) {
-				// e.g., int foo(struct S) {}
-				auto inst = new ast::StructInstType( agg->name );
-				auto obj = new ast::ObjectDecl( cur->location, "", inst );
-				obj->linkage = linkage;
-				*out++ = obj;
-				delete agg;
-			} else if ( ast::UnionDecl * agg = dynamic_cast<ast::UnionDecl *>( decl ) ) {
-				// e.g., int foo(union U) {}
-				auto inst = new ast::UnionInstType( agg->name );
-				auto obj = new ast::ObjectDecl( cur->location,
-					"", inst, nullptr, ast::Storage::Classes(),
-					linkage );
-				*out++ = obj;
-			} else if ( ast::EnumDecl * agg = dynamic_cast<ast::EnumDecl *>( decl ) ) {
-				// e.g., int foo(enum E) {}
-				auto inst = new ast::EnumInstType( agg->name );
-				auto obj = new ast::ObjectDecl( cur->location,
-					"",
-					inst,
-					nullptr,
-					ast::Storage::Classes(),
-					linkage
-				);
-				*out++ = obj;
-			} else {
-				assertf( false, "buildList: Could not convert to ast::DeclWithType." );
-			} // if
-		} catch ( SemanticErrorException & e ) {
-			errors.append( e );
-		} // try
-	} // for
-
-	if ( ! errors.isEmpty() ) {
-		throw errors;
-	} // if
-} // buildList
-
-void buildTypeList( const DeclarationNode * firstNode,
-		std::vector<ast::ptr<ast::Type>> & outputList ) {
-	SemanticErrorException errors;
-	std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
-
-	for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
-		try {
-			* out++ = cur->buildType();
-		} catch ( SemanticErrorException & e ) {
-			errors.append( e );
-		} // try
-	} // for
-
-	if ( ! errors.isEmpty() ) {
-		throw errors;
-	} // if
-} // buildTypeList
-
-ast::Decl * DeclarationNode::build() const {
-	if ( ! error.empty() ) SemanticError( this, error + " in declaration of " );
-
-	if ( asmStmt ) {
-		auto stmt = strict_dynamic_cast<ast::AsmStmt *>( asmStmt->build() );
-		return new ast::AsmDecl( stmt->location, stmt );
-	} // if
-	if ( directiveStmt ) {
-		auto stmt = strict_dynamic_cast<ast::DirectiveStmt *>( directiveStmt->build() );
-		return new ast::DirectiveDecl( stmt->location, stmt );
-	} // if
-
-	if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
-		// otype is internally converted to dtype + otype parameters
-		static const ast::TypeDecl::Kind kindMap[] = { ast::TypeDecl::Dtype, ast::TypeDecl::Dtype, ast::TypeDecl::Dtype, ast::TypeDecl::Ftype, ast::TypeDecl::Ttype, ast::TypeDecl::Dimension };
-		static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == ast::TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
-		assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
-		ast::TypeDecl * ret = new ast::TypeDecl( location,
-			*name,
-			ast::Storage::Classes(),
-			(ast::Type *)nullptr,
-			kindMap[ variable.tyClass ],
-			variable.tyClass == ast::TypeDecl::Otype || variable.tyClass == ast::TypeDecl::DStype,
-			variable.initializer ? variable.initializer->buildType() : nullptr
-		);
-		buildList( variable.assertions, ret->assertions );
-		return ret;
-	} // if
-
-	if ( type ) {
-		// Function specifiers can only appear on a function definition/declaration.
-		//
-		//    inline _Noreturn int f();			// allowed
-		//    inline _Noreturn int g( int i );	// allowed
-		//    inline _Noreturn int i;			// disallowed
-		if ( type->kind != TypeData::Function && funcSpecs.any() ) {
-			SemanticError( this, "invalid function specifier for " );
-		} // if
-		// Forall qualifier can only appear on a function/aggregate definition/declaration.
-		//
-		//    forall int f();					// allowed
-		//    forall int g( int i );			// allowed
-		//    forall int i;						// disallowed
-		if ( type->kind != TypeData::Function && type->forall ) {
-			SemanticError( this, "invalid type qualifier for " );
-		} // if
-		bool isDelete = initializer && initializer->get_isDelete();
-		ast::Decl * decl = buildDecl(
-			type,
-			name ? *name : string( "" ),
-			storageClasses,
-			maybeBuild( bitfieldWidth ),
-			funcSpecs,
-			linkage,
-			asmName,
-			isDelete ? nullptr : maybeBuild( initializer ),
-			copy( attributes )
-		)->set_extension( extension );
-		if ( isDelete ) {
-			auto dwt = strict_dynamic_cast<ast::DeclWithType *>( decl );
-			dwt->isDeleted = true;
-		}
-		return decl;
-	} // if
-
-	if ( assert.condition ) {
-		auto cond = maybeBuild( assert.condition );
-		auto msg = strict_dynamic_cast<ast::ConstantExpr *>( maybeCopy( assert.message ) );
-		return new ast::StaticAssertDecl( location, cond, msg );
-	}
-
-	// SUE's cannot have function specifiers, either
-	//
-	//    inline _Noreturn struct S { ... };		// disallowed
-	//    inline _Noreturn enum   E { ... };		// disallowed
-	if ( funcSpecs.any() ) {
-		SemanticError( this, "invalid function specifier for " );
-	} // if
-	if ( enumInLine ) {
-		return new ast::InlineMemberDecl( location,
-			*name, (ast::Type*)nullptr, storageClasses, linkage );
-	} // if
-	assertf( name, "ObjectDecl must a have name\n" );
-	auto ret = new ast::ObjectDecl( location,
-		*name,
-		(ast::Type*)nullptr,
-		maybeBuild( initializer ),
-		storageClasses,
-		linkage,
-		maybeBuild( bitfieldWidth )
-	);
-	ret->asmName = asmName;
-	ret->extension = extension;
-	return ret;
-}
-
-ast::Type * DeclarationNode::buildType() const {
-	assert( type );
-
-	switch ( type->kind ) {
-	case TypeData::Aggregate: {
-		ast::BaseInstType * ret =
-			buildComAggInst( type, copy( attributes ), linkage );
-		buildList( type->aggregate.actuals, ret->params );
-		return ret;
-	}
-	case TypeData::Symbolic: {
-		ast::TypeInstType * ret = new ast::TypeInstType(
-			*type->symbolic.name,
-			// This is just a default, the true value is not known yet.
-			ast::TypeDecl::Dtype,
-			buildQualifiers( type ),
-			copy( attributes ) );
-		buildList( type->symbolic.actuals, ret->params );
-		return ret;
-	}
-	default:
-		ast::Type * simpletypes = typebuild( type );
-		// copy because member is const
-		simpletypes->attributes = attributes;
-		return simpletypes;
-	} // switch
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/DeclarationNode.cpp
===================================================================
--- src/Parser/DeclarationNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/DeclarationNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,1030 @@
+//
+// 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.
+//
+// DeclarationNode.cpp --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Sat May 16 12:34:05 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri Feb 23 18:25:57 2024
+// Update Count     : 1533
+//
+
+#include "DeclarationNode.hpp"
+
+#include <cassert>                     // for assert, assertf, strict_dynami...
+#include <iterator>                    // for back_insert_iterator
+#include <list>                        // for list
+#include <memory>                      // for unique_ptr
+#include <ostream>                     // for operator<<, ostream, basic_ost...
+#include <string>                      // for string, operator+, allocator, ...
+
+#include "AST/Attribute.hpp"           // for Attribute
+#include "AST/Copy.hpp"                // for shallowCopy
+#include "AST/Decl.hpp"                // for Decl
+#include "AST/Expr.hpp"                // for Expr
+#include "AST/Print.hpp"               // for print
+#include "AST/Stmt.hpp"                // for AsmStmt, DirectiveStmt
+#include "AST/StorageClasses.hpp"      // for Storage::Class
+#include "AST/Type.hpp"                // for Type
+#include "Common/CodeLocation.hpp"     // for CodeLocation
+#include "Common/Iterate.hpp"          // for reverseIterate
+#include "Common/SemanticError.hpp"    // for SemanticError
+#include "Common/UniqueName.hpp"       // for UniqueName
+#include "Common/Utility.hpp"          // for copy, spliceBegin
+#include "Parser/ExpressionNode.hpp"   // for ExpressionNode
+#include "Parser/InitializerNode.hpp"  // for InitializerNode
+#include "Parser/StatementNode.hpp"    // for StatementNode
+#include "TypeData.hpp"                // for TypeData, TypeData::Aggregate_t
+#include "TypedefTable.hpp"            // for TypedefTable
+
+extern TypedefTable typedefTable;
+
+using namespace std;
+
+UniqueName DeclarationNode::anonymous( "__anonymous" );
+
+extern ast::Linkage::Spec linkage;						// defined in parser.yy
+
+DeclarationNode::DeclarationNode() :
+	linkage( ::linkage ) {
+
+	variable.tyClass = ast::TypeDecl::NUMBER_OF_KINDS;
+	variable.assertions = nullptr;
+	variable.initializer = nullptr;
+
+	assert.condition = nullptr;
+	assert.message = nullptr;
+}
+
+DeclarationNode::~DeclarationNode() {
+	delete name;
+
+	delete variable.assertions;
+	delete variable.initializer;
+
+	delete type;
+	delete bitfieldWidth;
+
+	delete asmStmt;
+	// asmName, no delete, passed to next stage
+	delete initializer;
+
+	delete assert.condition;
+	delete assert.message;
+}
+
+DeclarationNode * DeclarationNode::clone() const {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->next = maybeCopy( next );
+	newnode->name = name ? new string( *name ) : nullptr;
+
+	newnode->type = maybeCopy( type );
+	newnode->inLine = inLine;
+	newnode->storageClasses = storageClasses;
+	newnode->funcSpecs = funcSpecs;
+	newnode->bitfieldWidth = maybeCopy( bitfieldWidth );
+	newnode->enumeratorValue.reset( maybeCopy( enumeratorValue.get() ) );
+	newnode->hasEllipsis = hasEllipsis;
+	newnode->linkage = linkage;
+	newnode->asmName = maybeCopy( asmName );
+	newnode->attributes = attributes;
+	newnode->initializer = maybeCopy( initializer );
+	newnode->extension = extension;
+	newnode->asmStmt = maybeCopy( asmStmt );
+	newnode->error = error;
+
+	newnode->variable.tyClass = variable.tyClass;
+	newnode->variable.assertions = maybeCopy( variable.assertions );
+	newnode->variable.initializer = maybeCopy( variable.initializer );
+
+	newnode->assert.condition = maybeCopy( assert.condition );
+	newnode->assert.message = maybeCopy( assert.message );
+	return newnode;
+} // DeclarationNode::clone
+
+void DeclarationNode::print( std::ostream & os, int indent ) const {
+	os << string( indent, ' ' );
+	if ( name ) {
+		os << *name << ": ";
+	} // if
+
+	if ( linkage != ast::Linkage::Cforall ) {
+		os << ast::Linkage::name( linkage ) << " ";
+	} // if
+
+	ast::print( os, storageClasses );
+	ast::print( os, funcSpecs );
+
+	if ( type ) {
+		type->print( os, indent );
+	} else {
+		os << "untyped entity ";
+	} // if
+
+	if ( bitfieldWidth ) {
+		os << endl << string( indent + 2, ' ' ) << "with bitfield width ";
+		bitfieldWidth->printOneLine( os );
+	} // if
+
+	if ( initializer ) {
+		os << endl << string( indent + 2, ' ' ) << "with initializer ";
+		initializer->printOneLine( os );
+		os << " maybe constructed? " << initializer->get_maybeConstructed();
+	} // if
+
+	if ( ! attributes.empty() ) {
+		os << string( indent + 2, ' ' ) << "with attributes" << endl;
+		for ( ast::ptr<ast::Attribute> const & attr : reverseIterate( attributes ) ) {
+			os << string( indent + 4, ' ' );
+			ast::print( os, attr, indent + 2 );
+		} // for
+	} // if
+
+	os << endl;
+}
+
+void DeclarationNode::printList( std::ostream & os, int indent ) const {
+	ParseList::printList( os, indent );
+	if ( hasEllipsis ) {
+		os << string( indent, ' ' )  << "and a variable number of other arguments" << endl;
+	} // if
+}
+
+DeclarationNode * DeclarationNode::newFromTypeData( TypeData * type ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = type;
+	return newnode;
+} // DeclarationNode::newFromTypeData
+
+DeclarationNode * DeclarationNode::newStorageClass( ast::Storage::Classes sc ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->storageClasses = sc;
+	return newnode;
+} // DeclarationNode::newStorageClass
+
+DeclarationNode * DeclarationNode::newFuncSpecifier( ast::Function::Specs fs ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->funcSpecs = fs;
+	return newnode;
+} // DeclarationNode::newFuncSpecifier
+
+DeclarationNode * DeclarationNode::newAggregate( ast::AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::Aggregate );
+	newnode->type->aggregate.kind = kind;
+	newnode->type->aggregate.anon = name == nullptr;
+	newnode->type->aggregate.name = newnode->type->aggregate.anon ? new string( DeclarationNode::anonymous.newName() ) : name;
+	newnode->type->aggregate.actuals = actuals;
+	newnode->type->aggregate.fields = fields;
+	newnode->type->aggregate.body = body;
+	return newnode;
+} // DeclarationNode::newAggregate
+
+DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body, bool typed, DeclarationNode * base, EnumHiding hiding ) {
+	DeclarationNode * newnode = newAggregate( ast::AggregateDecl::Enum, name, nullptr, constants, body );
+	newnode->type->aggregate.typed = typed;
+	newnode->type->aggregate.hiding = hiding;
+	if ( base ) {
+		assert( typed );
+		assert( base->type );
+		newnode->type->base = base->type;
+		base->type = nullptr;
+		delete base;
+	} // if
+
+	return newnode;
+} // DeclarationNode::newEnum
+
+DeclarationNode * DeclarationNode::newName( const string * name ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	assert( ! newnode->name );
+	newnode->name = name;
+	return newnode;
+} // DeclarationNode::newName
+
+DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) {
+	DeclarationNode * newnode = newName( name );
+	newnode->enumeratorValue.reset( constant );
+	return newnode;
+} // DeclarationNode::newEnumConstant
+
+DeclarationNode * DeclarationNode::newEnumValueGeneric( const string * name, InitializerNode * init ) {
+	if ( nullptr == init ) {
+		return newName( name );
+	} else if ( init->get_expression() ) {
+		return newEnumConstant( name, init->get_expression() );
+	} else {
+		DeclarationNode * newnode = newName( name );
+		newnode->initializer = init;
+		return newnode;
+	} // if
+} // DeclarationNode::newEnumValueGeneric
+
+DeclarationNode * DeclarationNode::newEnumInLine( const std::string * name ) {
+	DeclarationNode * newnode = newName( name );
+	newnode->enumInLine = true;
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newTypeParam( ast::TypeDecl::Kind tc, const string * name ) {
+	DeclarationNode * newnode = newName( name );
+	newnode->type = nullptr;
+	newnode->variable.tyClass = tc;
+	newnode->variable.assertions = nullptr;
+	return newnode;
+} // DeclarationNode::newTypeParam
+
+DeclarationNode * DeclarationNode::newTrait( const string * name, DeclarationNode * params, DeclarationNode * asserts ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::Aggregate );
+	newnode->type->aggregate.name = name;
+	newnode->type->aggregate.kind = ast::AggregateDecl::Trait;
+	newnode->type->aggregate.params = params;
+	newnode->type->aggregate.fields = asserts;
+	return newnode;
+} // DeclarationNode::newTrait
+
+DeclarationNode * DeclarationNode::newTraitUse( const string * name, ExpressionNode * params ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::AggregateInst );
+	newnode->type->aggInst.aggregate = new TypeData( TypeData::Aggregate );
+	newnode->type->aggInst.aggregate->aggregate.kind = ast::AggregateDecl::Trait;
+	newnode->type->aggInst.aggregate->aggregate.name = name;
+	newnode->type->aggInst.params = params;
+	return newnode;
+} // DeclarationNode::newTraitUse
+
+DeclarationNode * DeclarationNode::newTypeDecl( const string * name, DeclarationNode * typeParams ) {
+	DeclarationNode * newnode = newName( name );
+	newnode->type = new TypeData( TypeData::Symbolic );
+	newnode->type->symbolic.isTypedef = false;
+	newnode->type->symbolic.params = typeParams;
+	return newnode;
+} // DeclarationNode::newTypeDecl
+
+DeclarationNode * DeclarationNode::newPointer( DeclarationNode * qualifiers, OperKinds kind ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( kind == OperKinds::PointTo ? TypeData::Pointer : TypeData::Reference );
+	if ( kind == OperKinds::And ) {
+		// T && is parsed as 'And' operator rather than two references => add a second reference type
+		TypeData * td = new TypeData( TypeData::Reference );
+		td->base = newnode->type;
+		newnode->type = td;
+	}
+	if ( qualifiers ) {
+		return newnode->addQualifiers( qualifiers );
+	} else {
+		return newnode;
+	} // if
+} // DeclarationNode::newPointer
+
+DeclarationNode * DeclarationNode::newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::Array );
+	newnode->type->array.dimension = size;
+	newnode->type->array.isStatic = isStatic;
+	newnode->type->array.isVarLen = size && !size->isExpressionType<ast::ConstantExpr *>();
+	return newnode->addQualifiers( qualifiers );
+} // DeclarationNode::newArray
+
+DeclarationNode * DeclarationNode::newVarArray( DeclarationNode * qualifiers ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::Array );
+	newnode->type->array.dimension = nullptr;
+	newnode->type->array.isStatic = false;
+	newnode->type->array.isVarLen = true;
+	return newnode->addQualifiers( qualifiers );
+}
+
+DeclarationNode * DeclarationNode::newBitfield( ExpressionNode * size ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->bitfieldWidth = size;
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newTuple( DeclarationNode * members ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::Tuple );
+	newnode->type->tuple = members;
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newTypeof( ExpressionNode * expr, bool basetypeof ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( basetypeof ? TypeData::Basetypeof : TypeData::Typeof );
+	newnode->type->typeexpr = expr;
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {
+	DeclarationNode * newnode = newName( name );
+	newnode->type = new TypeData( TypeData::Function );
+	newnode->type->function.params = param;
+	newnode->type->function.body = body;
+
+	if ( ret ) {
+		newnode->type->base = ret->type;
+		ret->type = nullptr;
+		delete ret;
+	} // if
+
+	return newnode;
+} // DeclarationNode::newFunction
+
+DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = nullptr;
+	std::vector<ast::ptr<ast::Expr>> exprs;
+	buildList( expr, exprs );
+	newnode->attributes.push_back( new ast::Attribute( *name, std::move( exprs ) ) );
+	delete name;
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newDirectiveStmt( StatementNode * stmt ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->directiveStmt = stmt;
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newAsmStmt( StatementNode * stmt ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->asmStmt = stmt;
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::newStaticAssert( ExpressionNode * condition, ast::Expr * message ) {
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->assert.condition = condition;
+	newnode->assert.message = message;
+	return newnode;
+}
+
+static void appendError( string & dst, const string & src ) {
+	if ( src.empty() ) return;
+	if ( dst.empty() ) { dst = src; return; }
+	dst += ", " + src;
+} // appendError
+
+void DeclarationNode::checkQualifiers( const TypeData * src, const TypeData * dst ) {
+	const ast::CV::Qualifiers qsrc = src->qualifiers, qdst = dst->qualifiers; // optimization
+	const ast::CV::Qualifiers duplicates = qsrc & qdst;
+
+	if ( duplicates.any() ) {
+		std::stringstream str;
+		str << "duplicate ";
+		ast::print( str, duplicates );
+		str << "qualifier(s)";
+		appendError( error, str.str() );
+	} // for
+} // DeclarationNode::checkQualifiers
+
+void DeclarationNode::checkSpecifiers( DeclarationNode * src ) {
+	ast::Function::Specs fsDups = funcSpecs & src->funcSpecs;
+	if ( fsDups.any() ) {
+		std::stringstream str;
+		str << "duplicate ";
+		ast::print( str, fsDups );
+		str << "function specifier(s)";
+		appendError( error, str.str() );
+	} // if
+
+	// Skip if everything is unset.
+	if ( storageClasses.any() && src->storageClasses.any() ) {
+		ast::Storage::Classes dups = storageClasses & src->storageClasses;
+		// Check for duplicates.
+		if ( dups.any() ) {
+			std::stringstream str;
+			str << "duplicate ";
+			ast::print( str, dups );
+			str << "storage class(es)";
+			appendError( error, str.str() );
+		// Check for conflicts.
+		} else if ( !src->storageClasses.is_threadlocal_any() ) {
+			std::stringstream str;
+			str << "conflicting ";
+			ast::print( str, ast::Storage::Classes( 1 << storageClasses.ffs() ) );
+			str << "& ";
+			ast::print( str, ast::Storage::Classes( 1 << src->storageClasses.ffs() ) );
+			str << "storage classes";
+			appendError( error, str.str() );
+			// FIX to preserve invariant of one basic storage specifier
+			src->storageClasses.reset();
+		}
+	} // if
+
+	appendError( error, src->error );
+} // DeclarationNode::checkSpecifiers
+
+DeclarationNode * DeclarationNode::copySpecifiers( DeclarationNode * q, bool copyattr ) {
+	funcSpecs |= q->funcSpecs;
+	storageClasses |= q->storageClasses;
+
+	if ( copyattr ) {
+		std::vector<ast::ptr<ast::Attribute>> tmp;
+		tmp.reserve( q->attributes.size() );
+		for ( auto const & attr : q->attributes ) {
+			tmp.emplace_back( ast::shallowCopy( attr.get() ) );
+		} // for
+		spliceBegin( attributes, tmp );
+	} // if
+
+	return this;
+} // DeclarationNode::copySpecifiers
+
+DeclarationNode * DeclarationNode::addQualifiers( DeclarationNode * q ) {
+	if ( ! q ) { return this; }							// empty qualifier
+
+	checkSpecifiers( q );
+	copySpecifiers( q );
+
+	if ( ! q->type ) { delete q; return this; }
+
+	if ( ! type ) {
+		type = q->type;									// reuse structure
+		q->type = nullptr;
+		delete q;
+		return this;
+	} // if
+
+	checkQualifiers( type, q->type );
+	TypeData::BuiltinType const builtin = type->builtintype;
+	if ( (builtin == TypeData::Zero || builtin == TypeData::One) && q->type->qualifiers.any() && error.length() == 0 ) {
+		SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, TypeData::builtinTypeNames[builtin] );
+	} // if
+	type = ::addQualifiers( type, q->type );
+	q->type = nullptr;
+
+	delete q;
+	return this;
+} // addQualifiers
+
+DeclarationNode * DeclarationNode::addType( DeclarationNode * o, bool copyattr ) {
+	if ( !o ) return this;
+
+	checkSpecifiers( o );
+	copySpecifiers( o, copyattr );
+	if ( o->type ) {
+		type = ::addType( type, o->type, o->attributes );
+		o->type = nullptr;
+	} // if
+	if ( o->bitfieldWidth ) {
+		bitfieldWidth = o->bitfieldWidth;
+	} // if
+
+	// there may be typedefs chained onto the type
+	if ( o->next ) {
+		set_last( o->next->clone() );
+	} // if
+
+	delete o;
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addEnumBase( DeclarationNode * o ) {
+	if ( o && o->type ) {
+		type->base = o->type;
+	} // if
+	delete o;
+	return this;
+}
+
+// This code handles a special issue with the attribute transparent_union.
+//
+//    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
+//
+// Here the attribute aligned goes with the typedef_name, so variables declared of this type are
+// aligned.  However, the attribute transparent_union must be moved from the typedef_name to
+// alias union U.  Currently, this is the only know attribute that must be moved from typedef to
+// alias.
+static void moveUnionAttribute( DeclarationNode * decl, DeclarationNode * unionDecl ) {
+	assert( decl->type->kind == TypeData::Symbolic );
+	assert( decl->type->symbolic.isTypedef );
+	assert( unionDecl->type->kind == TypeData::Aggregate );
+
+	if ( unionDecl->type->aggregate.kind != ast::AggregateDecl::Union ) return;
+
+	// Ignore the Aggregate_t::attributes. Why did we add that before the rework?
+	for ( auto attr = decl->attributes.begin() ; attr != decl->attributes.end() ; ) {
+		if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
+			unionDecl->attributes.emplace_back( attr->release() );
+			attr = decl->attributes.erase( attr );
+		} else {
+			++attr;
+		}
+	}
+}
+
+// Helper for addTypedef, handles the case where the typedef wraps an
+// aggregate declaration (not a type), returns a chain of nodes.
+static DeclarationNode * addTypedefAggr(
+		DeclarationNode * olddecl, TypeData * newtype ) {
+	TypeData *& oldaggr = olddecl->type->aggInst.aggregate;
+
+	// Handle anonymous aggregates: typedef struct { int i; } foo
+	// Give the typedefed type a consistent name across translation units.
+	if ( oldaggr->aggregate.anon ) {
+		delete oldaggr->aggregate.name;
+		oldaggr->aggregate.name = new string( "__anonymous_" + *olddecl->name );
+		oldaggr->aggregate.anon = false;
+		oldaggr->qualifiers.reset();
+	}
+
+	// Replace the wrapped TypeData with a forward declaration.
+	TypeData * newaggr = new TypeData( TypeData::Aggregate );
+	newaggr->aggregate.kind = oldaggr->aggregate.kind;
+	newaggr->aggregate.name = oldaggr->aggregate.name ? new string( *oldaggr->aggregate.name ) : nullptr;
+	newaggr->aggregate.body = false;
+	newaggr->aggregate.anon = oldaggr->aggregate.anon;
+	newaggr->aggregate.typed = oldaggr->aggregate.typed;
+	newaggr->aggregate.hiding = oldaggr->aggregate.hiding;
+	swap( newaggr, oldaggr );
+
+	newtype->base = olddecl->type;
+	olddecl->type = newtype;
+	DeclarationNode * newdecl = new DeclarationNode;
+	newdecl->type = newaggr;
+	newdecl->next = olddecl;
+
+	moveUnionAttribute( olddecl, newdecl );
+
+	return newdecl;
+}
+
+// Wrap the declaration in a typedef. It actually does that by modifying the
+// existing declaration, and may split it into two declarations.
+// This only happens if the wrapped type is actually a declaration of a SUE
+// type. If it does, the DeclarationNode for the SUE declaration is the node
+// returned, make sure later transformations are applied to the right node.
+DeclarationNode * DeclarationNode::addTypedef() {
+	TypeData * newtype = new TypeData( TypeData::Symbolic );
+	newtype->symbolic.params = nullptr;
+	newtype->symbolic.isTypedef = true;
+	newtype->symbolic.name = name ? new string( *name ) : nullptr;
+	// If this typedef is wrapping an aggregate, separate them out.
+	if ( TypeData::AggregateInst == type->kind
+			&& TypeData::Aggregate == type->aggInst.aggregate->kind
+			&& type->aggInst.aggregate->aggregate.body ) {
+		return addTypedefAggr( this, newtype );
+	// There is no internal declaration, just a type.
+	} else {
+		newtype->base = type;
+		type = newtype;
+		return this;
+	}
+}
+
+DeclarationNode * DeclarationNode::addAssertions( DeclarationNode * assertions ) {
+	if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
+		extend( variable.assertions, assertions );
+		return this;
+	} // if
+
+	assert( type );
+	assert( TypeData::Symbolic == type->kind );
+	extend( type->symbolic.assertions, assertions );
+
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addName( string * newname ) {
+	assert( ! name );
+	name = newname;
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addAsmName( DeclarationNode * newname ) {
+	assert( ! asmName );
+	asmName = newname ? newname->asmName : nullptr;
+	return this->addQualifiers( newname );
+}
+
+DeclarationNode * DeclarationNode::addBitfield( ExpressionNode * size ) {
+	bitfieldWidth = size;
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addVarArgs() {
+	assert( type );
+	hasEllipsis = true;
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addFunctionBody( StatementNode * body, ExpressionNode * withExprs ) {
+	assert( type );
+	assert( type->kind == TypeData::Function );
+	assert( ! type->function.body );
+	type->function.body = body;
+	type->function.withExprs = withExprs;
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addOldDeclList( DeclarationNode * list ) {
+	assert( type );
+	assert( type->kind == TypeData::Function );
+	assert( ! type->function.oldDeclList );
+	type->function.oldDeclList = list;
+	return this;
+}
+
+DeclarationNode * DeclarationNode::setBase( TypeData * newType ) {
+	if ( type ) {
+		type->setLastBase( newType );
+	} else {
+		type = newType;
+	} // if
+	return this;
+}
+
+DeclarationNode * DeclarationNode::copyAttribute( DeclarationNode * a ) {
+	if ( a ) {
+		spliceBegin( attributes, a->attributes );
+		a->attributes.clear();
+	} // if
+	return this;
+} // copyAttribute
+
+DeclarationNode * DeclarationNode::addPointer( DeclarationNode * p ) {
+	if ( p ) {
+		assert( p->type->kind == TypeData::Pointer || p->type->kind == TypeData::Reference );
+		setBase( p->type );
+		p->type = nullptr;
+		copyAttribute( p );
+		delete p;
+	} // if
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addArray( DeclarationNode * a ) {
+	if ( a ) {
+		assert( a->type->kind == TypeData::Array );
+		setBase( a->type );
+		a->type = nullptr;
+		copyAttribute( a );
+		delete a;
+	} // if
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addNewPointer( DeclarationNode * p ) {
+	if ( !p ) return this;
+	assert( p->type->kind == TypeData::Pointer || p->type->kind == TypeData::Reference );
+	if ( type ) {
+		p->type->base = makeNewBase( type );
+		type = nullptr;
+	} // if
+	delete this;
+	return p;
+}
+
+DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) {
+	if ( !a ) return this;
+	assert( a->type->kind == TypeData::Array );
+	if ( type ) {
+		a->type->setLastBase( makeNewBase( type ) );
+		type = nullptr;
+	} // if
+	delete this;
+	return a;
+}
+
+DeclarationNode * DeclarationNode::addParamList( DeclarationNode * params ) {
+	TypeData * ftype = new TypeData( TypeData::Function );
+	ftype->function.params = params;
+	setBase( ftype );
+	return this;
+}
+
+static TypeData * addIdListToType( TypeData * type, DeclarationNode * ids ) {
+	if ( type ) {
+		if ( type->kind != TypeData::Function ) {
+			type->base = addIdListToType( type->base, ids );
+		} else {
+			type->function.idList = ids;
+		} // if
+		return type;
+	} else {
+		TypeData * newtype = new TypeData( TypeData::Function );
+		newtype->function.idList = ids;
+		return newtype;
+	} // if
+} // addIdListToType
+
+DeclarationNode * DeclarationNode::addIdList( DeclarationNode * ids ) {
+	type = addIdListToType( type, ids );
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addInitializer( InitializerNode * init ) {
+	initializer = init;
+	return this;
+}
+
+DeclarationNode * DeclarationNode::addTypeInitializer( DeclarationNode * init ) {
+	assertf( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS, "Called addTypeInitializer on something that isn't a type variable." );
+	variable.initializer = init;
+	return this;
+}
+
+DeclarationNode * DeclarationNode::cloneType( string * name ) {
+	DeclarationNode * newnode = newName( name );
+	newnode->type = maybeCopy( type );
+	newnode->copySpecifiers( this );
+	return newnode;
+}
+
+DeclarationNode * DeclarationNode::cloneBaseType( DeclarationNode * o, bool copyattr ) {
+	if ( ! o ) return nullptr;
+	o->copySpecifiers( this, copyattr );
+	if ( type ) {
+		o->type = ::cloneBaseType( type, o->type );
+	} // if
+	return o;
+}
+
+DeclarationNode * DeclarationNode::extractAggregate() const {
+	if ( type ) {
+		TypeData * ret = typeextractAggregate( type );
+		if ( ret ) {
+			DeclarationNode * newnode = new DeclarationNode;
+			newnode->type = ret;
+			if ( ret->kind == TypeData::Aggregate ) {
+				newnode->attributes.swap( ret->aggregate.attributes );
+			} // if
+			return newnode;
+		} // if
+	} // if
+	return nullptr;
+}
+
+// Get the non-anonymous name of the instance type of the declaration,
+// if one exists.
+static const std::string * getInstTypeOfName( ast::Decl * decl ) {
+	if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
+		if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) {
+			if ( aggr->name.find("anonymous") == std::string::npos ) {
+				return &aggr->name;
+			}
+		}
+	}
+	return nullptr;
+}
+
+void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList ) {
+	SemanticErrorException errors;
+	std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
+
+	for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
+		try {
+			bool extracted_named = false;
+
+			if ( DeclarationNode * extr = cur->extractAggregate() ) {
+				assert( cur->type );
+
+				if ( ast::Decl * decl = extr->build() ) {
+					*out++ = decl;
+
+					// need to remember the cases where a declaration contains an anonymous aggregate definition
+					assert( extr->type );
+					if ( extr->type->kind == TypeData::Aggregate ) {
+						// typedef struct { int A } B is the only case?
+						extracted_named = ! extr->type->aggregate.anon;
+					} else {
+						extracted_named = true;
+					}
+				} // if
+				delete extr;
+			} // if
+
+			if ( ast::Decl * decl = cur->build() ) {
+				if ( "" == decl->name && !cur->get_inLine() ) {
+					// Don't include anonymous declaration for named aggregates,
+					// but do include them for anonymous aggregates, e.g.:
+					// struct S {
+					//   struct T { int x; }; // no anonymous member
+					//   struct { int y; };   // anonymous member
+					//   struct T;            // anonymous member
+					// };
+					if ( extracted_named ) {
+						continue;
+					}
+
+					if ( auto name = getInstTypeOfName( decl ) ) {
+						// Temporary: warn about anonymous member declarations of named types, since
+						// this conflicts with the syntax for the forward declaration of an anonymous type.
+						SemanticWarning( cur->location, Warning::AggrForwardDecl, name->c_str() );
+					}
+				} // if
+				*out++ = decl;
+			} // if
+		} catch ( SemanticErrorException & e ) {
+			errors.append( e );
+		} // try
+	} // for
+
+	if ( ! errors.isEmpty() ) {
+		throw errors;
+	} // if
+} // buildList
+
+// currently only builds assertions, function parameters, and return values
+void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
+	SemanticErrorException errors;
+	std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
+
+	for ( const DeclarationNode * cur = firstNode; cur; cur = cur->next ) {
+		try {
+			ast::Decl * decl = cur->build();
+			assertf( decl, "buildList: build for ast::DeclWithType." );
+			if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
+				dwt->location = cur->location;
+				*out++ = dwt;
+			} else if ( ast::StructDecl * agg = dynamic_cast<ast::StructDecl *>( decl ) ) {
+				// e.g., int foo(struct S) {}
+				auto inst = new ast::StructInstType( agg->name );
+				auto obj = new ast::ObjectDecl( cur->location, "", inst );
+				obj->linkage = linkage;
+				*out++ = obj;
+				delete agg;
+			} else if ( ast::UnionDecl * agg = dynamic_cast<ast::UnionDecl *>( decl ) ) {
+				// e.g., int foo(union U) {}
+				auto inst = new ast::UnionInstType( agg->name );
+				auto obj = new ast::ObjectDecl( cur->location,
+					"", inst, nullptr, ast::Storage::Classes(),
+					linkage );
+				*out++ = obj;
+			} else if ( ast::EnumDecl * agg = dynamic_cast<ast::EnumDecl *>( decl ) ) {
+				// e.g., int foo(enum E) {}
+				auto inst = new ast::EnumInstType( agg->name );
+				auto obj = new ast::ObjectDecl( cur->location,
+					"",
+					inst,
+					nullptr,
+					ast::Storage::Classes(),
+					linkage
+				);
+				*out++ = obj;
+			} else {
+				assertf( false, "buildList: Could not convert to ast::DeclWithType." );
+			} // if
+		} catch ( SemanticErrorException & e ) {
+			errors.append( e );
+		} // try
+	} // for
+
+	if ( ! errors.isEmpty() ) {
+		throw errors;
+	} // if
+} // buildList
+
+void buildTypeList( const DeclarationNode * firstNode,
+		std::vector<ast::ptr<ast::Type>> & outputList ) {
+	SemanticErrorException errors;
+	std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
+
+	for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
+		try {
+			* out++ = cur->buildType();
+		} catch ( SemanticErrorException & e ) {
+			errors.append( e );
+		} // try
+	} // for
+
+	if ( ! errors.isEmpty() ) {
+		throw errors;
+	} // if
+} // buildTypeList
+
+ast::Decl * DeclarationNode::build() const {
+	if ( ! error.empty() ) SemanticError( this, error + " in declaration of " );
+
+	if ( asmStmt ) {
+		auto stmt = strict_dynamic_cast<ast::AsmStmt *>( asmStmt->build() );
+		return new ast::AsmDecl( stmt->location, stmt );
+	} // if
+	if ( directiveStmt ) {
+		auto stmt = strict_dynamic_cast<ast::DirectiveStmt *>( directiveStmt->build() );
+		return new ast::DirectiveDecl( stmt->location, stmt );
+	} // if
+
+	if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
+		// otype is internally converted to dtype + otype parameters
+		static const ast::TypeDecl::Kind kindMap[] = { ast::TypeDecl::Dtype, ast::TypeDecl::Dtype, ast::TypeDecl::Dtype, ast::TypeDecl::Ftype, ast::TypeDecl::Ttype, ast::TypeDecl::Dimension };
+		static_assert( sizeof(kindMap) / sizeof(kindMap[0]) == ast::TypeDecl::NUMBER_OF_KINDS, "DeclarationNode::build: kindMap is out of sync." );
+		assertf( variable.tyClass < sizeof(kindMap)/sizeof(kindMap[0]), "Variable's tyClass is out of bounds." );
+		ast::TypeDecl * ret = new ast::TypeDecl( location,
+			*name,
+			ast::Storage::Classes(),
+			(ast::Type *)nullptr,
+			kindMap[ variable.tyClass ],
+			variable.tyClass == ast::TypeDecl::Otype || variable.tyClass == ast::TypeDecl::DStype,
+			variable.initializer ? variable.initializer->buildType() : nullptr
+		);
+		buildList( variable.assertions, ret->assertions );
+		return ret;
+	} // if
+
+	if ( type ) {
+		// Function specifiers can only appear on a function definition/declaration.
+		//
+		//    inline _Noreturn int f();			// allowed
+		//    inline _Noreturn int g( int i );	// allowed
+		//    inline _Noreturn int i;			// disallowed
+		if ( type->kind != TypeData::Function && funcSpecs.any() ) {
+			SemanticError( this, "invalid function specifier for " );
+		} // if
+		// Forall qualifier can only appear on a function/aggregate definition/declaration.
+		//
+		//    forall int f();					// allowed
+		//    forall int g( int i );			// allowed
+		//    forall int i;						// disallowed
+		if ( type->kind != TypeData::Function && type->forall ) {
+			SemanticError( this, "invalid type qualifier for " );
+		} // if
+		bool isDelete = initializer && initializer->get_isDelete();
+		ast::Decl * decl = buildDecl(
+			type,
+			name ? *name : string( "" ),
+			storageClasses,
+			maybeBuild( bitfieldWidth ),
+			funcSpecs,
+			linkage,
+			asmName,
+			isDelete ? nullptr : maybeBuild( initializer ),
+			copy( attributes )
+		)->set_extension( extension );
+		if ( isDelete ) {
+			auto dwt = strict_dynamic_cast<ast::DeclWithType *>( decl );
+			dwt->isDeleted = true;
+		}
+		return decl;
+	} // if
+
+	if ( assert.condition ) {
+		auto cond = maybeBuild( assert.condition );
+		auto msg = strict_dynamic_cast<ast::ConstantExpr *>( maybeCopy( assert.message ) );
+		return new ast::StaticAssertDecl( location, cond, msg );
+	}
+
+	// SUE's cannot have function specifiers, either
+	//
+	//    inline _Noreturn struct S { ... };		// disallowed
+	//    inline _Noreturn enum   E { ... };		// disallowed
+	if ( funcSpecs.any() ) {
+		SemanticError( this, "invalid function specifier for " );
+	} // if
+	if ( enumInLine ) {
+		return new ast::InlineMemberDecl( location,
+			*name, (ast::Type*)nullptr, storageClasses, linkage );
+	} // if
+	assertf( name, "ObjectDecl must a have name\n" );
+	auto ret = new ast::ObjectDecl( location,
+		*name,
+		(ast::Type*)nullptr,
+		maybeBuild( initializer ),
+		storageClasses,
+		linkage,
+		maybeBuild( bitfieldWidth )
+	);
+	ret->asmName = asmName;
+	ret->extension = extension;
+	return ret;
+}
+
+ast::Type * DeclarationNode::buildType() const {
+	assert( type );
+
+	switch ( type->kind ) {
+	case TypeData::Aggregate: {
+		ast::BaseInstType * ret =
+			buildComAggInst( type, copy( attributes ), linkage );
+		buildList( type->aggregate.actuals, ret->params );
+		return ret;
+	}
+	case TypeData::Symbolic: {
+		ast::TypeInstType * ret = new ast::TypeInstType(
+			*type->symbolic.name,
+			// This is just a default, the true value is not known yet.
+			ast::TypeDecl::Dtype,
+			buildQualifiers( type ),
+			copy( attributes ) );
+		buildList( type->symbolic.actuals, ret->params );
+		return ret;
+	}
+	default:
+		ast::Type * simpletypes = typebuild( type );
+		// copy because member is const
+		simpletypes->attributes = attributes;
+		return simpletypes;
+	} // switch
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/DeclarationNode.h
===================================================================
--- src/Parser/DeclarationNode.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,173 +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.
-//
-// DeclarationNode.h --
-//
-// Author           : Andrew Beach
-// Created On       : Wed Apr  5 11:38:00 2023
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb 17 09:24:12 2024
-// Update Count     : 4
-//
-
-#pragma once
-
-#include "ParseNode.h"
-
-struct TypeData;
-struct InitializerNode;
-
-struct DeclarationNode final : public ParseList<DeclarationNode> {
-	static DeclarationNode * newFromTypeData( TypeData * );
-	static DeclarationNode * newStorageClass( ast::Storage::Classes );
-	static DeclarationNode * newFuncSpecifier( ast::Function::Specs );
-	static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
-	static DeclarationNode * newAggregate( ast::AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
-	static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed, DeclarationNode * base = nullptr, EnumHiding hiding = EnumHiding::Visible );
-	static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
-	static DeclarationNode * newEnumValueGeneric( const std::string * name, InitializerNode * init );
-	static DeclarationNode * newEnumInLine( const std::string * name );
-	static DeclarationNode * newName( const std::string * );
-	static DeclarationNode * newTypeParam( ast::TypeDecl::Kind, const std::string * );
-	static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );
-	static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params );
-	static DeclarationNode * newTypeDecl( const std::string * name, DeclarationNode * typeParams );
-	static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind );
-	static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic );
-	static DeclarationNode * newVarArray( DeclarationNode * qualifiers );
-	static DeclarationNode * newBitfield( ExpressionNode * size );
-	static DeclarationNode * newTuple( DeclarationNode * members );
-	static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
-	static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
-	static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
-	static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement
-	static DeclarationNode * newStaticAssert( ExpressionNode * condition, ast::Expr * message );
-
-	DeclarationNode();
-	~DeclarationNode();
-	DeclarationNode * clone() const override;
-
-	DeclarationNode * addQualifiers( DeclarationNode * );
-	void checkQualifiers( const TypeData *, const TypeData * );
-	void checkSpecifiers( DeclarationNode * );
-	DeclarationNode * copySpecifiers( DeclarationNode *, bool = true );
-	DeclarationNode * addType( DeclarationNode *, bool = true );
-	DeclarationNode * addTypedef();
-	DeclarationNode * addEnumBase( DeclarationNode * );
-	DeclarationNode * addAssertions( DeclarationNode * );
-	DeclarationNode * addName( std::string * );
-	DeclarationNode * addAsmName( DeclarationNode * );
-	DeclarationNode * addBitfield( ExpressionNode * size );
-	DeclarationNode * addVarArgs();
-	DeclarationNode * addFunctionBody( StatementNode * body, ExpressionNode * with = nullptr );
-	DeclarationNode * addOldDeclList( DeclarationNode * list );
-	DeclarationNode * setBase( TypeData * newType );
-	DeclarationNode * copyAttribute( DeclarationNode * attr );
-	DeclarationNode * addPointer( DeclarationNode * qualifiers );
-	DeclarationNode * addArray( DeclarationNode * array );
-	DeclarationNode * addNewPointer( DeclarationNode * pointer );
-	DeclarationNode * addNewArray( DeclarationNode * array );
-	DeclarationNode * addParamList( DeclarationNode * list );
-	DeclarationNode * addIdList( DeclarationNode * list ); // old-style functions
-	DeclarationNode * addInitializer( InitializerNode * init );
-	DeclarationNode * addTypeInitializer( DeclarationNode * init );
-
-	DeclarationNode * cloneType( std::string * newName );
-	DeclarationNode * cloneBaseType( DeclarationNode * newdecl, bool = true );
-
-	virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
-	virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
-
-	ast::Decl * build() const;
-	ast::Type * buildType() const;
-
-	ast::Linkage::Spec get_linkage() const { return linkage; }
-	DeclarationNode * extractAggregate() const;
-	bool has_enumeratorValue() const { return (bool)enumeratorValue; }
-	ExpressionNode * consume_enumeratorValue() const { return const_cast<DeclarationNode *>(this)->enumeratorValue.release(); }
-
-	bool get_extension() const { return extension; }
-	DeclarationNode * set_extension( bool exten ) { extension = exten; return this; }
-
-	bool get_inLine() const { return inLine; }
-	DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
-
-	const std::string * name = nullptr;
-
-	struct Variable_t {
-		ast::TypeDecl::Kind tyClass;
-		DeclarationNode * assertions;
-		DeclarationNode * initializer;
-	};
-	Variable_t variable;
-
-	struct StaticAssert_t {
-		ExpressionNode * condition;
-		ast::Expr * message;
-	};
-	StaticAssert_t assert;
-
-	TypeData * type = nullptr;
-
-	bool inLine = false;
-	bool enumInLine = false;
-	ast::Function::Specs funcSpecs;
-	ast::Storage::Classes storageClasses;
-
-	ExpressionNode * bitfieldWidth = nullptr;
-	std::unique_ptr<ExpressionNode> enumeratorValue;
-	bool hasEllipsis = false;
-	ast::Linkage::Spec linkage;
-	ast::Expr * asmName = nullptr;
-	std::vector<ast::ptr<ast::Attribute>> attributes;
-	InitializerNode * initializer = nullptr;
-	bool extension = false;
-	std::string error;
-	StatementNode * asmStmt = nullptr;
-	StatementNode * directiveStmt = nullptr;
-
-	static UniqueName anonymous;
-}; // DeclarationNode
-
-static inline ast::Type * maybeMoveBuildType( const DeclarationNode * orig ) {
-	ast::Type * ret = orig ? orig->buildType() : nullptr;
-	delete orig;
-	return ret;
-}
-
-// This generic buildList is here along side its overloads.
-template<typename AstType, typename NodeType,
-		template<typename, typename...> class Container, typename... Args>
-void buildList( NodeType * firstNode,
-		Container<ast::ptr<AstType>, Args...> & output ) {
-	SemanticErrorException errors;
-	std::back_insert_iterator<Container<ast::ptr<AstType>, Args...>> out( output );
-
-	for ( NodeType * cur = firstNode ; cur ; cur = cur->next ) {
-		try {
-			AstType * node = dynamic_cast<AstType *>( maybeBuild( cur ) );
-			assertf( node, "buildList: Did not build node of correct type." );
-			*out++ = node;
-		} catch ( SemanticErrorException & e ) {
-			errors.append( e );
-		} // try
-	} // for
-	if ( ! errors.isEmpty() ) {
-		throw errors;
-	} // if
-}
-
-void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList );
-void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList );
-void buildTypeList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Type>> & outputList );
-
-template<typename AstType, typename NodeType,
-		template<typename, typename...> class Container, typename... Args>
-void buildMoveList( NodeType * firstNode,
-		Container<ast::ptr<AstType>, Args...> & output ) {
-	buildList<AstType, NodeType, Container, Args...>( firstNode, output );
-	delete firstNode;
-}
Index: src/Parser/DeclarationNode.hpp
===================================================================
--- src/Parser/DeclarationNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/DeclarationNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,173 @@
+//
+// 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.
+//
+// DeclarationNode.hpp --
+//
+// Author           : Andrew Beach
+// Created On       : Wed Apr  5 11:38:00 2023
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Feb 17 09:24:12 2024
+// Update Count     : 4
+//
+
+#pragma once
+
+#include "ParseNode.hpp"
+
+struct TypeData;
+struct InitializerNode;
+
+struct DeclarationNode final : public ParseList<DeclarationNode> {
+	static DeclarationNode * newFromTypeData( TypeData * );
+	static DeclarationNode * newStorageClass( ast::Storage::Classes );
+	static DeclarationNode * newFuncSpecifier( ast::Function::Specs );
+	static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
+	static DeclarationNode * newAggregate( ast::AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
+	static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed, DeclarationNode * base = nullptr, EnumHiding hiding = EnumHiding::Visible );
+	static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
+	static DeclarationNode * newEnumValueGeneric( const std::string * name, InitializerNode * init );
+	static DeclarationNode * newEnumInLine( const std::string * name );
+	static DeclarationNode * newName( const std::string * );
+	static DeclarationNode * newTypeParam( ast::TypeDecl::Kind, const std::string * );
+	static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );
+	static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params );
+	static DeclarationNode * newTypeDecl( const std::string * name, DeclarationNode * typeParams );
+	static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind );
+	static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic );
+	static DeclarationNode * newVarArray( DeclarationNode * qualifiers );
+	static DeclarationNode * newBitfield( ExpressionNode * size );
+	static DeclarationNode * newTuple( DeclarationNode * members );
+	static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
+	static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
+	static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
+	static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement
+	static DeclarationNode * newStaticAssert( ExpressionNode * condition, ast::Expr * message );
+
+	DeclarationNode();
+	~DeclarationNode();
+	DeclarationNode * clone() const override;
+
+	DeclarationNode * addQualifiers( DeclarationNode * );
+	void checkQualifiers( const TypeData *, const TypeData * );
+	void checkSpecifiers( DeclarationNode * );
+	DeclarationNode * copySpecifiers( DeclarationNode *, bool = true );
+	DeclarationNode * addType( DeclarationNode *, bool = true );
+	DeclarationNode * addTypedef();
+	DeclarationNode * addEnumBase( DeclarationNode * );
+	DeclarationNode * addAssertions( DeclarationNode * );
+	DeclarationNode * addName( std::string * );
+	DeclarationNode * addAsmName( DeclarationNode * );
+	DeclarationNode * addBitfield( ExpressionNode * size );
+	DeclarationNode * addVarArgs();
+	DeclarationNode * addFunctionBody( StatementNode * body, ExpressionNode * with = nullptr );
+	DeclarationNode * addOldDeclList( DeclarationNode * list );
+	DeclarationNode * setBase( TypeData * newType );
+	DeclarationNode * copyAttribute( DeclarationNode * attr );
+	DeclarationNode * addPointer( DeclarationNode * qualifiers );
+	DeclarationNode * addArray( DeclarationNode * array );
+	DeclarationNode * addNewPointer( DeclarationNode * pointer );
+	DeclarationNode * addNewArray( DeclarationNode * array );
+	DeclarationNode * addParamList( DeclarationNode * list );
+	DeclarationNode * addIdList( DeclarationNode * list ); // old-style functions
+	DeclarationNode * addInitializer( InitializerNode * init );
+	DeclarationNode * addTypeInitializer( DeclarationNode * init );
+
+	DeclarationNode * cloneType( std::string * newName );
+	DeclarationNode * cloneBaseType( DeclarationNode * newdecl, bool = true );
+
+	virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
+	virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
+
+	ast::Decl * build() const;
+	ast::Type * buildType() const;
+
+	ast::Linkage::Spec get_linkage() const { return linkage; }
+	DeclarationNode * extractAggregate() const;
+	bool has_enumeratorValue() const { return (bool)enumeratorValue; }
+	ExpressionNode * consume_enumeratorValue() const { return const_cast<DeclarationNode *>(this)->enumeratorValue.release(); }
+
+	bool get_extension() const { return extension; }
+	DeclarationNode * set_extension( bool exten ) { extension = exten; return this; }
+
+	bool get_inLine() const { return inLine; }
+	DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
+
+	const std::string * name = nullptr;
+
+	struct Variable_t {
+		ast::TypeDecl::Kind tyClass;
+		DeclarationNode * assertions;
+		DeclarationNode * initializer;
+	};
+	Variable_t variable;
+
+	struct StaticAssert_t {
+		ExpressionNode * condition;
+		ast::Expr * message;
+	};
+	StaticAssert_t assert;
+
+	TypeData * type = nullptr;
+
+	bool inLine = false;
+	bool enumInLine = false;
+	ast::Function::Specs funcSpecs;
+	ast::Storage::Classes storageClasses;
+
+	ExpressionNode * bitfieldWidth = nullptr;
+	std::unique_ptr<ExpressionNode> enumeratorValue;
+	bool hasEllipsis = false;
+	ast::Linkage::Spec linkage;
+	ast::Expr * asmName = nullptr;
+	std::vector<ast::ptr<ast::Attribute>> attributes;
+	InitializerNode * initializer = nullptr;
+	bool extension = false;
+	std::string error;
+	StatementNode * asmStmt = nullptr;
+	StatementNode * directiveStmt = nullptr;
+
+	static UniqueName anonymous;
+}; // DeclarationNode
+
+static inline ast::Type * maybeMoveBuildType( const DeclarationNode * orig ) {
+	ast::Type * ret = orig ? orig->buildType() : nullptr;
+	delete orig;
+	return ret;
+}
+
+// This generic buildList is here along side its overloads.
+template<typename AstType, typename NodeType,
+		template<typename, typename...> class Container, typename... Args>
+void buildList( NodeType * firstNode,
+		Container<ast::ptr<AstType>, Args...> & output ) {
+	SemanticErrorException errors;
+	std::back_insert_iterator<Container<ast::ptr<AstType>, Args...>> out( output );
+
+	for ( NodeType * cur = firstNode ; cur ; cur = cur->next ) {
+		try {
+			AstType * node = dynamic_cast<AstType *>( maybeBuild( cur ) );
+			assertf( node, "buildList: Did not build node of correct type." );
+			*out++ = node;
+		} catch ( SemanticErrorException & e ) {
+			errors.append( e );
+		} // try
+	} // for
+	if ( ! errors.isEmpty() ) {
+		throw errors;
+	} // if
+}
+
+void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList );
+void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList );
+void buildTypeList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Type>> & outputList );
+
+template<typename AstType, typename NodeType,
+		template<typename, typename...> class Container, typename... Args>
+void buildMoveList( NodeType * firstNode,
+		Container<ast::ptr<AstType>, Args...> & output ) {
+	buildList<AstType, NodeType, Container, Args...>( firstNode, output );
+	delete firstNode;
+}
Index: src/Parser/ExpressionNode.cc
===================================================================
--- src/Parser/ExpressionNode.cc	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,784 +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.
-//
-// ExpressionNode.cc --
-//
-// Author           : Peter A. Buhr
-// Created On       : Sat May 16 13:17:07 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Dec 14 18:57:07 2023
-// Update Count     : 1087
-//
-
-#include "ExpressionNode.h"
-
-#include <cassert>                 // for assert
-#include <stdio.h>                 // for sscanf, size_t
-#include <climits>                 // for LLONG_MAX, LONG_MAX, INT_MAX, UINT...
-#include <list>                    // for list
-#include <sstream>                 // for basic_istream::operator>>, basic_i...
-#include <string>                  // for string, operator+, operator==
-
-#include "AST/BasicKind.hpp"       // for BasicKind
-#include "AST/Expr.hpp"            // for NameExpr
-#include "AST/Type.hpp"            // for Type, LengthFlag, DimentionFlag
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild, CodeLo...
-#include "DeclarationNode.h"       // for DeclarationNode
-#include "InitializerNode.h"       // for InitializerNode
-#include "TypeData.h"              // for addType, build_basic_type, build_c...
-#include "parserutility.h"         // for notZeroExpr
-
-using namespace std;
-
-//##############################################################################
-
-// Difficult to separate extra parts of constants during lexing because actions are not allow in the middle of patterns:
-//
-//		prefix action constant action suffix
-//
-// Alternatively, breaking a pattern using BEGIN does not work if the following pattern can be empty:
-//
-//		constant BEGIN CONT ...
-//		<CONT>(...)? BEGIN 0 ... // possible empty suffix
-//
-// because the CONT rule is NOT triggered if the pattern is empty. Hence, constants are reparsed here to determine their
-// type.
-
-// static inline bool checkH( char c ) { return c == 'h' || c == 'H'; }
-// static inline bool checkZ( char c ) { return c == 'z' || c == 'Z'; }
-// static inline bool checkU( char c ) { return c == 'u' || c == 'U'; }
-static inline bool checkF( char c ) { return c == 'f' || c == 'F'; }
-static inline bool checkD( char c ) { return c == 'd' || c == 'D'; }
-static inline bool checkF80( char c ) { return c == 'w' || c == 'W'; }
-static inline bool checkF128( char c ) { return c == 'q' || c == 'Q'; }
-static inline bool checkL( char c ) { return c == 'l' || c == 'L'; }
-static inline bool checkI( char c ) { return c == 'i' || c == 'I'; }
-static inline bool checkB( char c ) { return c == 'b' || c == 'B'; }
-static inline bool checkX( char c ) { return c == 'x' || c == 'X'; }
-// static inline bool checkN( char c ) { return c == 'n' || c == 'N'; }
-
-void lnthSuffix( string & str, int & type, int & ltype ) {
-	// 'u' can appear before or after length suffix
-	string::size_type posn = str.find_last_of( "lL" );
-
-	if ( posn == string::npos ) return;					// no suffix
-	size_t end = str.length() - 1;
-	if ( posn == end ) { type = 3; return; }			// no length after 'l' => long
-
-	string::size_type next = posn + 1;					// advance to length
-	if ( str[next] == '3' ) {							// 32
-		type = ltype = 2;
-	} else if ( str[next] == '6' ) {					// 64
-		type = ltype = 3;
-	} else if ( str[next] == '8' ) {					// 8
-		type = ltype = 1;
-	} else if ( str[next] == '1' ) {
-		if ( str[next + 1] == '6' ) {					// 16
-			type = ltype = 0;
-		} else {										// 128
-			type = 5; ltype = 6;
-		} // if
-	} // if
-
-	char fix = '\0';
-	if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ?
-	str.erase( posn );									// remove length suffix and possibly uU
-	if ( type == 5 ) {									// L128 does not need uU
-		end = str.length() - 1;
-		if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove
-	} else if ( fix != '\0' ) str += fix;				// put 'uU' back if removed
-} // lnthSuffix
-
-void valueToType( unsigned long long int & v, bool dec, int & type, bool & Unsigned ) {
-	// use value to determine type
-	if ( v <= INT_MAX ) {								// signed int
-		type = 2;
-	} else if ( v <= UINT_MAX && ! dec ) {				// unsigned int
-		type = 2;
-		Unsigned = true;								// unsigned
-	} else if ( v <= LONG_MAX ) {						// signed long int
-		type = 3;
-	} else if ( v <= ULONG_MAX && ( ! dec || LONG_MAX == LLONG_MAX ) ) { // signed long int
-		type = 3;
-		Unsigned = true;								// unsigned long int
-	} else if ( v <= LLONG_MAX ) {						// signed long long int
-		type = 4;
-	} else {											// unsigned long long int
-		type = 4;
-		Unsigned = true;								// unsigned long long int
-	} // if
-} // valueToType
-
-static void scanbin( string & str, unsigned long long int & v ) {
-	v = 0;
-	size_t last = str.length() - 1;						// last subscript of constant
-	for ( unsigned int i = 2;; ) {						// ignore prefix
-		if ( str[i] == '1' ) v |= 1;
-		i += 1;
-		if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
-		v <<= 1;
-	} // for
-} // scanbin
-
-ast::Expr * build_constantInteger(
-		const CodeLocation & location, string & str ) {
-	static const ast::BasicKind kind[2][6] = {
-		// short (h) must be before char (hh) because shorter type has the longer suffix
-		{ ast::BasicKind::ShortSignedInt, ast::BasicKind::SignedChar, ast::BasicKind::SignedInt, ast::BasicKind::LongSignedInt, ast::BasicKind::LongLongSignedInt, /* BasicKind::SignedInt128 */ ast::BasicKind::LongLongSignedInt, },
-		{ ast::BasicKind::ShortUnsignedInt, ast::BasicKind::UnsignedChar, ast::BasicKind::UnsignedInt, ast::BasicKind::LongUnsignedInt, ast::BasicKind::LongLongUnsignedInt, /* BasicKind::UnsignedInt128 */ ast::BasicKind::LongLongUnsignedInt, },
-	};
-
-	static const char * lnthsInt[2][6] = {
-		{ "int16_t",  "int8_t",  "int32_t",  "int64_t",  "size_t",  "uintptr_t", },
-		{ "uint16_t", "uint8_t", "uint32_t", "uint64_t", "size_t",  "uintptr_t", },
-	}; // lnthsInt
-
-	string str2( "0x0" );
-	unsigned long long int v, v2 = 0;					// converted integral value
-	ast::Expr * ret, * ret2;
-
-	int type = -1;										// 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
-	int ltype = -1;										// 0 => 16 bits, 1 => 8 bits, 2 => 32 bits, 3 => 64 bits, 4 => size_t, 5 => intptr, 6 => pointer
-	bool dec = true, Unsigned = false;					// decimal, unsigned constant
-
-	// special constants
-	if ( str == "0" ) {
-		ret = new ast::ConstantExpr( location, new ast::ZeroType(), str, 0 );
-		goto CLEANUP;
-	} // if
-	if ( str == "1" ) {
-		ret = new ast::ConstantExpr( location, new ast::OneType(), str, 1 );
-		goto CLEANUP;
-	} // if
-
-	// 'u' can appear before or after length suffix
-	if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true;
-
-	if ( isdigit( str[str.length() - 1] ) ) {			// no suffix ?
-		lnthSuffix( str, type, ltype );					// could have length suffix
-	} else {
-		// At least one digit in integer constant, so safe to backup while looking for suffix.
-		// This declaration and the comma expressions in the conditions mimic
-		// the declare and check pattern allowed in later compiler versions.
-		// (Only some early compilers/C++ standards do not support it.)
-		string::size_type posn;
-		// pointer value
-		if ( posn = str.find_last_of( "pP" ), posn != string::npos ) {
-			ltype = 5; str.erase( posn, 1 );
-		// size_t
-		} else if ( posn = str.find_last_of( "zZ" ), posn != string::npos ) {
-			Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 );
-		// signed char
-		} else if ( posn = str.rfind( "hh" ), posn != string::npos ) {
-			type = 1; str.erase( posn, 2 );
-		// signed char
-		} else if ( posn = str.rfind( "HH" ), posn != string::npos ) {
-			type = 1; str.erase( posn, 2 );
-		// short
-		} else if ( posn = str.find_last_of( "hH" ), posn != string::npos ) {
-			type = 0; str.erase( posn, 1 );
-		// int (natural number)
-		} else if ( posn = str.find_last_of( "nN" ), posn != string::npos ) {
-			type = 2; str.erase( posn, 1 );
-		} else if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) {
-			type = 4;
-		} else {
-			lnthSuffix( str, type, ltype );
-		} // if
-	} // if
-
-	// Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate
-
-#if ! defined(__SIZEOF_INT128__)
-	if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target \"%s\"", str.c_str() );
-#endif // ! __SIZEOF_INT128__
-
-	if ( str[0] == '0' ) {								// radix character ?
-		dec = false;
-		if ( checkX( str[1] ) ) {						// hex constant ?
-			if ( type < 5 ) {							// not L128 ?
-				sscanf( (char *)str.c_str(), "%llx", &v );
-#if defined(__SIZEOF_INT128__)
-			} else {									// hex int128 constant
-				unsigned int len = str.length();
-				if ( len > (2 + 16 + 16) ) SemanticError( yylloc, "128-bit hexadecimal constant to large \"%s\"", str.c_str() );
-				// hex digits < 2^64
-				if ( len > (2 + 16) ) {
-					str2 = "0x" + str.substr( len - 16 );
-					sscanf( (char *)str2.c_str(), "%llx", &v2 );
-					str = str.substr( 0, len - 16 );
-				} // if
-				sscanf( (char *)str.c_str(), "%llx", &v );
-#endif // __SIZEOF_INT128__
-			} // if
-			//printf( "%llx %llu\n", v, v );
-		} else if ( checkB( str[1] ) ) {				// binary constant ?
-#if defined(__SIZEOF_INT128__)
-			unsigned int len = str.length();
-			if ( type == 5 && len > 2 + 64 ) {
-				if ( len > 2 + 64 + 64 ) SemanticError( yylloc, "128-bit binary constant to large \"%s\".", str.c_str() );
-				str2 = "0b" + str.substr( len - 64 );
-				str = str.substr( 0, len - 64 );
-				scanbin( str2, v2 );
-			} // if
-#endif // __SIZEOF_INT128__
-			scanbin( str, v );
-			//printf( "%#llx %llu\n", v, v );
-		} else {										// octal constant
-			if ( type < 5 ) {							// not L128 ?
-				sscanf( (char *)str.c_str(), "%llo", &v );
-#if defined(__SIZEOF_INT128__)
-			} else {									// octal int128 constant
-				unsigned int len = str.length();
-				if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large \"%s\"", str.c_str() );
-				char buf[32];
-				if ( len <= 1 + 21 ) {					// value < 21 octal digitis
-					sscanf( (char *)str.c_str(), "%llo", &v );
-				} else {
-					sscanf( &str[len - 21], "%llo", &v );
-					__int128 val = v;					// accumulate bits
-					str[len - 21] ='\0';				// shorten string
-					sscanf( &str[len == 43 ? 1 : 0], "%llo", &v );
-					val |= (__int128)v << 63;			// store bits
-					if ( len == 1 + 43 ) {				// most significant 2 bits ?
-						str[2] = '\0';					// shorten string
-						sscanf( &str[1], "%llo", &v );	// process most significant 2 bits
-						val |= (__int128)v << 126;		// store bits
-					} // if
-					v = val >> 64; v2 = (uint64_t)val;	// replace octal constant with 2 hex constants
-					sprintf( buf, "%#llx", v2 );
-					str2 = buf;
-				} // if
-				sprintf( buf, "%#llx", v );
-				str = buf;
-#endif // __SIZEOF_INT128__
-			} // if
-			//printf( "%#llo %llu\n", v, v );
-		} // if
-	} else {											// decimal constant ?
-		if ( type < 5 ) {								// not L128 ?
-			sscanf( (char *)str.c_str(), "%llu", &v );
-#if defined(__SIZEOF_INT128__)
-		} else {										// decimal int128 constant
-			#define P10_UINT64 10'000'000'000'000'000'000ULL // 19 zeroes
-			unsigned int len = str.length();
-			if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") )
-				SemanticError( yylloc, "128-bit decimal constant to large \"%s\".", str.c_str() );
-			char buf[32];
-			if ( len <= 19 ) {							// value < 19 decimal digitis
-				sscanf( (char *)str.c_str(), "%llu", &v );
-			} else {
-				sscanf( &str[len - 19], "%llu", &v );
-				__int128 val = v;						// accumulate bits
-				str[len - 19] ='\0';					// shorten string
-				sscanf( &str[len == 39 ? 1 : 0], "%llu", &v );
-				val += (__int128)v * (__int128)P10_UINT64; // store bits
-				if ( len == 39 ) {						// most significant 2 bits ?
-					str[1] = '\0';						// shorten string
-					sscanf( &str[0], "%llu", &v );		// process most significant 2 bits
-					val += (__int128)v * (__int128)P10_UINT64 * (__int128)P10_UINT64; // store bits
-				} // if
-				v = val >> 64; v2 = (uint64_t)val;		// replace decimal constant with 2 hex constants
-				sprintf( buf, "%#llx", v2 );
-				str2 = buf;
-			} // if
-			sprintf( buf, "%#llx", v );
-			str = buf;
-#endif // __SIZEOF_INT128__
-		} // if
-		//printf( "%llu\n", v );
-	} // if
-
-	if ( type == -1 ) {									// no suffix => determine type from value size
-		valueToType( v, dec, type, Unsigned );
-	} // if
-	/* printf( "%s %llo %s %llo\n", str.c_str(), v, str2.c_str(), v2 ); */
-
-	//if ( !( 0 <= type && type <= 6 ) ) { printf( "%s %lu %d %s\n", fred.c_str(), fred.length(), type, str.c_str() ); }
-	assert( 0 <= type && type <= 6 );
-
-	// Constant type is correct for overload resolving.
-	ret = new ast::ConstantExpr( location,
-		new ast::BasicType( kind[Unsigned][type] ), str, v );
-	if ( Unsigned && type < 2 ) {						// hh or h, less than int ?
-		// int i = -1uh => 65535 not -1, so cast is necessary for unsigned, which unfortunately eliminates warnings for large values.
-		ret = new ast::CastExpr( location,
-			ret,
-			new ast::BasicType( kind[Unsigned][type] ),
-			ast::ExplicitCast );
-	} else if ( ltype != -1 ) {							// explicit length ?
-		if ( ltype == 6 ) {								// int128, (int128)constant
-			ret2 = new ast::ConstantExpr( location,
-				new ast::BasicType( ast::BasicKind::LongLongSignedInt ),
-				str2,
-				v2 );
-			ret = build_compoundLiteral( location,
-				DeclarationNode::newFromTypeData(
-					addType(
-						build_basic_type( TypeData::Int128 ),
-						build_signedness( TypeData::Unsigned ) ) ),
-				new InitializerNode(
-					(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true )
-			);
-		} else {										// explicit length, (length_type)constant
-			ret = new ast::CastExpr( location,
-				ret,
-				new ast::TypeInstType( lnthsInt[Unsigned][ltype], ast::TypeDecl::Dtype ),
-				ast::ExplicitCast );
-			if ( ltype == 5 ) {							// pointer, intptr( (uintptr_t)constant )
-				ret = build_func( location,
-					new ExpressionNode(
-						build_varref( location, new string( "intptr" ) ) ),
-					new ExpressionNode( ret ) );
-			} // if
-		} // if
-	} // if
-
-  CLEANUP: ;
-	delete &str;										// created by lex
-	return ret;
-} // build_constantInteger
-
-
-static inline void checkFnxFloat( string & str, size_t last, bool & explnth, int & type ) {
-	string::size_type posn;
-	// floating-point constant has minimum of 2 characters, 1. or .1, so safe to look ahead
-	if ( str[1] == 'x' ) {								// hex ?
-		posn = str.find_last_of( "pP" );				// back for exponent (must have)
-		posn = str.find_first_of( "fF", posn + 1 );		// forward for size (fF allowed in hex constant)
-	} else {
-		posn = str.find_last_of( "fF" );				// back for size (fF not allowed)
-	} // if
-  if ( posn == string::npos ) return;
-	explnth = true;
-	posn += 1;											// advance to size
-	if ( str[posn] == '3' ) {							// 32
-		if ( str[last] != 'x' ) type = 6;
-		else type = 7;
-	} else if ( str[posn] == '6' ) {					// 64
-		if ( str[last] != 'x' ) type = 8;
-		else type = 9;
-	} else if ( str[posn] == '8' ) {					// 80
-		type = 3;
-	} else if ( str[posn] == '1' ) {					// 16/128
-		if ( str[posn + 1] == '6' ) {					// 16
-			type = 5;
-		} else {										// 128
-			if ( str[last] != 'x' ) type = 10;
-			else type = 11;
-		} // if
-	} else {
-		assertf( false, "internal error, bad floating point length %s", str.c_str() );
-	} // if
-} // checkFnxFloat
-
-
-ast::Expr * build_constantFloat(
-		const CodeLocation & location, string & str ) {
-	static const ast::BasicKind kind[2][12] = {
-		{ ast::BasicKind::Float, ast::BasicKind::Double, ast::BasicKind::LongDouble, ast::BasicKind::uuFloat80, ast::BasicKind::uuFloat128, ast::BasicKind::uFloat16, ast::BasicKind::uFloat32, ast::BasicKind::uFloat32x, ast::BasicKind::uFloat64, ast::BasicKind::uFloat64x, ast::BasicKind::uFloat128, ast::BasicKind::uFloat128x },
-		{ ast::BasicKind::FloatComplex, ast::BasicKind::DoubleComplex, ast::BasicKind::LongDoubleComplex, ast::BasicKind::NUMBER_OF_BASIC_TYPES, ast::BasicKind::NUMBER_OF_BASIC_TYPES, ast::BasicKind::uFloat16Complex, ast::BasicKind::uFloat32Complex, ast::BasicKind::uFloat32xComplex, ast::BasicKind::uFloat64Complex, ast::BasicKind::uFloat64xComplex, ast::BasicKind::uFloat128Complex, ast::BasicKind::uFloat128xComplex },
-	};
-
-	// floating-point constant has minimum of 2 characters 1. or .1
-	size_t last = str.length() - 1;
-	double v;
-	int type;											// 0 => float, 1 => double, 3 => long double, ...
-	bool complx = false;								// real, complex
-	bool explnth = false;								// explicit literal length
-
-	sscanf( str.c_str(), "%lg", &v );
-
-	if ( checkI( str[last] ) ) {						// imaginary ?
-		complx = true;
-		last -= 1;										// backup one character
-	} // if
-
-	if ( checkF( str[last] ) ) {						// float ?
-		type = 0;
-	} else if ( checkD( str[last] ) ) {					// double ?
-		type = 1;
-	} else if ( checkL( str[last] ) ) {					// long double ?
-		type = 2;
-	} else if ( checkF80( str[last] ) ) {				// __float80 ?
-		type = 3;
-	} else if ( checkF128( str[last] ) ) {				// __float128 ?
-		type = 4;
-	} else {
-		type = 1;										// double (default if no suffix)
-		checkFnxFloat( str, last, explnth, type );
-	} // if
-
-	if ( ! complx && checkI( str[last - 1] ) ) {		// imaginary ?
-		complx = true;
-	} // if
-
-	assert( 0 <= type && type < 12 );
-	ast::Expr * ret = new ast::ConstantExpr( location,
-		new ast::BasicType( kind[complx][type] ),
-		str,
-		v );
-	// explicit length ?
-	if ( explnth ) {
-		ret = new ast::CastExpr( location,
-			ret,
-			new ast::BasicType( kind[complx][type] ),
-			ast::ExplicitCast );
-	} // if
-
-	delete &str;										// created by lex
-	return ret;
-} // build_constantFloat
-
-static void sepString( string & str, string & units, char delimit ) {
-	string::size_type posn = str.find_last_of( delimit ) + 1;
-	if ( posn != str.length() ) {
-		units = "?" + str.substr( posn );				// extract units
-		str.erase( posn );								// remove units
-	} // if
-} // sepString
-
-ast::Expr * build_constantChar( const CodeLocation & location, string & str ) {
-	string units;										// units
-	sepString( str, units, '\'' );						// separate constant from units
-
-	ast::Expr * ret = new ast::ConstantExpr( location,
-		new ast::BasicType( ast::BasicKind::Char ),
-		str,
-		(unsigned long long int)(unsigned char)str[1] );
-	if ( units.length() != 0 ) {
-		ret = new ast::UntypedExpr( location,
-			new ast::NameExpr( location, units ),
-			{ ret } );
-	} // if
-
-	delete &str;										// created by lex
-	return ret;
-} // build_constantChar
-
-ast::Expr * build_constantStr(
-		const CodeLocation & location,
-		string & str ) {
-	assert( str.length() > 0 );
-	string units;										// units
-	sepString( str, units, '"' );						// separate constant from units
-
-	ast::Type * strtype;
-	switch ( str[0] ) {									// str has >= 2 characters, i.e, null string "" => safe to look at subscripts 0/1
-	case 'u':
-		if ( str[1] == '8' ) goto Default;				// utf-8 characters => array of char
-		// lookup type of associated typedef
-		strtype = new ast::TypeInstType( "char16_t", ast::TypeDecl::Dtype );
-		break;
-	case 'U':
-		strtype = new ast::TypeInstType( "char32_t", ast::TypeDecl::Dtype );
-		break;
-	case 'L':
-		strtype = new ast::TypeInstType( "wchar_t", ast::TypeDecl::Dtype );
-		break;
-	Default:											// char default string type
-	default:
-		strtype = new ast::BasicType( ast::BasicKind::Char );
-	} // switch
-	ast::ArrayType * at = new ast::ArrayType(
-		strtype,
-		// Length is adjusted: +1 for '\0' and -2 for '"'
-		ast::ConstantExpr::from_ulong( location, str.size() + 1 - 2 ),
-		ast::FixedLen,
-		ast::DynamicDim );
-	ast::Expr * ret = new ast::ConstantExpr( location, at, str, std::nullopt );
-	if ( units.length() != 0 ) {
-		ret = new ast::UntypedExpr( location,
-			new ast::NameExpr( location, units ),
-			{ ret } );
-	} // if
-
-	delete &str;										// created by lex
-	return ret;
-} // build_constantStr
-
-ast::Expr * build_field_name_FLOATING_FRACTIONconstant(
-		const CodeLocation & location, const string & str ) {
-	if ( str.find_first_not_of( "0123456789", 1 ) != string::npos ) SemanticError( yylloc, "invalid tuple index \"%s\".", str.c_str() );
-	ast::Expr * ret = build_constantInteger( location,
-		*new string( str.substr(1) ) );
-	delete &str;
-	return ret;
-} // build_field_name_FLOATING_FRACTIONconstant
-
-ast::Expr * build_field_name_FLOATING_DECIMALconstant(
-		const CodeLocation & location, const string & str ) {
-	if ( str[str.size() - 1] != '.' ) SemanticError( yylloc, "invalid tuple index \"%s\".", str.c_str() );
-	ast::Expr * ret = build_constantInteger(
-		location, *new string( str.substr( 0, str.size()-1 ) ) );
-	delete &str;
-	return ret;
-} // build_field_name_FLOATING_DECIMALconstant
-
-ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation & location,
-		const string & str ) {
-	// str is of the form A.B -> separate at the . and return member expression
-	int a, b;
-	char dot;
-	stringstream ss( str );
-	ss >> a >> dot >> b;
-	auto ret = new ast::UntypedMemberExpr( location,
-		ast::ConstantExpr::from_int( location, b ),
-		ast::ConstantExpr::from_int( location, a )
-	);
-	delete &str;
-	return ret;
-} // build_field_name_FLOATINGconstant
-
-ast::Expr * make_field_name_fraction_constants( const CodeLocation & location,
-		ast::Expr * fieldName,
-		ast::Expr * fracts ) {
-	if ( nullptr == fracts ) {
-		return fieldName;
-	} else if ( auto memberExpr = dynamic_cast<ast::UntypedMemberExpr *>( fracts ) ) {
-		memberExpr->member = make_field_name_fraction_constants( location,
-			fieldName,
-			ast::mutate( memberExpr->aggregate.get() ) );
-		return memberExpr;
-	} else {
-		return new ast::UntypedMemberExpr( location, fracts, fieldName );
-	} // if
-} // make_field_name_fraction_constants
-
-ast::Expr * build_field_name_fraction_constants( const CodeLocation & location,
-		ast::Expr * fieldName,
-		ExpressionNode * fracts ) {
-	return make_field_name_fraction_constants( location, fieldName, maybeMoveBuild( fracts ) );
-} // build_field_name_fraction_constants
-
-ast::NameExpr * build_varref( const CodeLocation & location,
-		const string * name ) {
-	ast::NameExpr * expr = new ast::NameExpr( location, *name );
-	delete name;
-	return expr;
-} // build_varref
-
-ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location,
-		const DeclarationNode * decl_node,
-		const ast::NameExpr * name ) {
-	ast::Decl * newDecl = maybeBuild( decl_node );
-	if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) {
-		if ( const ast::Type * t = newDeclWithType->get_type() ) {
-			if ( auto typeInst = dynamic_cast<const ast::TypeInstType *>( t ) ) {
-				newDecl = new ast::EnumDecl( location, typeInst->name );
-			}
-		}
-	}
-	return new ast::QualifiedNameExpr( location, newDecl, name->name );
-}
-
-ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location,
-		const ast::EnumDecl * decl,
-		const ast::NameExpr * name ) {
-	return new ast::QualifiedNameExpr( location, decl, name->name );
-}
-
-ast::DimensionExpr * build_dimensionref( const CodeLocation & location,
-		const string * name ) {
-	ast::DimensionExpr * expr = new ast::DimensionExpr( location, *name );
-	delete name;
-	return expr;
-} // build_varref
-
-// TODO: get rid of this and OperKinds and reuse code from OperatorTable
-static const char * OperName[] = {						// must harmonize with OperKinds
-	// diadic
-	"SizeOf", "AlignOf", "OffsetOf", "?+?", "?-?", "?\\?", "?*?", "?/?", "?%?", "||", "&&",
-	"?|?", "?&?", "?^?", "Cast", "?<<?", "?>>?", "?<?", "?>?", "?<=?", "?>=?", "?==?", "?!=?",
-	"?=?", "?@=?", "?\\=?", "?*=?", "?/=?", "?%=?", "?+=?", "?-=?", "?<<=?", "?>>=?", "?&=?", "?^=?", "?|=?",
-	"?[?]", "...",
-	// monadic
-	"+?", "-?", "AddressOf", "*?", "!?", "~?", "++?", "?++", "--?", "?--",
-}; // OperName
-
-ast::Expr * build_cast( const CodeLocation & location,
-		DeclarationNode * decl_node,
-		ExpressionNode * expr_node,
-		ast::CastExpr::CastKind kind ) {
-	ast::Type * targetType = maybeMoveBuildType( decl_node );
-	if ( dynamic_cast<ast::VoidType *>( targetType ) ) {
-		delete targetType;
-		return new ast::CastExpr( location,
-			maybeMoveBuild( expr_node ),
-			ast::ExplicitCast, kind );
-	} else {
-		return new ast::CastExpr( location,
-			maybeMoveBuild( expr_node ),
-			targetType,
-			ast::ExplicitCast, kind );
-	} // if
-} // build_cast
-
-ast::Expr * build_keyword_cast( const CodeLocation & location,
-		ast::AggregateDecl::Aggregate target,
-		ExpressionNode * expr_node ) {
-	return new ast::KeywordCastExpr( location,
-		maybeMoveBuild( expr_node ),
-		target
-	);
-}
-
-ast::Expr * build_virtual_cast( const CodeLocation & location,
-		DeclarationNode * decl_node,
-		ExpressionNode * expr_node ) {
-	return new ast::VirtualCastExpr( location,
-		maybeMoveBuild( expr_node ),
-		maybeMoveBuildType( decl_node )
-	);
-} // build_virtual_cast
-
-ast::Expr * build_fieldSel( const CodeLocation & location,
-		ExpressionNode * expr_node,
-		ast::Expr * member ) {
-	return new ast::UntypedMemberExpr( location,
-		member,
-		maybeMoveBuild( expr_node )
-	);
-} // build_fieldSel
-
-ast::Expr * build_pfieldSel( const CodeLocation & location,
-		ExpressionNode * expr_node,
-		ast::Expr * member ) {
-	auto deref = new ast::UntypedExpr( location,
-		new ast::NameExpr( location, "*?" )
-	);
-	deref->location = expr_node->location;
-	deref->args.push_back( maybeMoveBuild( expr_node ) );
-	auto ret = new ast::UntypedMemberExpr( location, member, deref );
-	return ret;
-} // build_pfieldSel
-
-ast::Expr * build_offsetOf( const CodeLocation & location,
-		DeclarationNode * decl_node,
-		ast::NameExpr * member ) {
-	ast::Expr * ret = new ast::UntypedOffsetofExpr( location,
-		maybeMoveBuildType( decl_node ),
-		member->name
-	);
-	ret->result = new ast::BasicType( ast::BasicKind::LongUnsignedInt );
-	delete member;
-	return ret;
-} // build_offsetOf
-
-ast::Expr * build_and_or( const CodeLocation & location,
-		ExpressionNode * expr_node1,
-		ExpressionNode * expr_node2,
-		ast::LogicalFlag flag ) {
-	return new ast::LogicalExpr( location,
-		maybeMoveBuild( expr_node1 ),
-		maybeMoveBuild( expr_node2 ),
-		flag
-	);
-} // build_and_or
-
-ast::Expr * build_unary_val( const CodeLocation & location,
-		OperKinds op,
-		ExpressionNode * expr_node ) {
-	std::vector<ast::ptr<ast::Expr>> args;
-	args.push_back( maybeMoveBuild( expr_node ) );
-	return new ast::UntypedExpr( location,
-		new ast::NameExpr( location, OperName[ (int)op ] ),
-		std::move( args )
-	);
-} // build_unary_val
-
-ast::Expr * build_binary_val( const CodeLocation & location,
-		OperKinds op,
-		ExpressionNode * expr_node1,
-		ExpressionNode * expr_node2 ) {
-	std::vector<ast::ptr<ast::Expr>> args;
-	args.push_back( maybeMoveBuild( expr_node1 ) );
-	args.push_back( maybeMoveBuild( expr_node2 ) );
-	return new ast::UntypedExpr( location,
-		new ast::NameExpr( location, OperName[ (int)op ] ),
-		std::move( args )
-	);
-} // build_binary_val
-
-ast::Expr * build_cond( const CodeLocation & location,
-		ExpressionNode * expr_node1,
-		ExpressionNode * expr_node2,
-		ExpressionNode * expr_node3 ) {
-	return new ast::ConditionalExpr( location,
-		maybeMoveBuild( expr_node1 ),
-		maybeMoveBuild( expr_node2 ),
-		maybeMoveBuild( expr_node3 )
-	);
-} // build_cond
-
-ast::Expr * build_tuple( const CodeLocation & location,
-		ExpressionNode * expr_node ) {
-	std::vector<ast::ptr<ast::Expr>> exprs;
-	buildMoveList( expr_node, exprs );
-	return new ast::UntypedTupleExpr( location, std::move( exprs ) );
-} // build_tuple
-
-ast::Expr * build_func( const CodeLocation & location,
-		ExpressionNode * function,
-		ExpressionNode * expr_node ) {
-	std::vector<ast::ptr<ast::Expr>> args;
-	buildMoveList( expr_node, args );
-	return new ast::UntypedExpr( location,
-		maybeMoveBuild( function ),
-		std::move( args )
-	);
-} // build_func
-
-ast::Expr * build_compoundLiteral( const CodeLocation & location,
-		DeclarationNode * decl_node,
-		InitializerNode * kids ) {
-	// compound literal type
-	ast::Decl * newDecl = maybeBuild( decl_node );
-	// non-sue compound-literal type
-	if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) {
-		return new ast::CompoundLiteralExpr( location,
-			newDeclWithType->get_type(),
-			maybeMoveBuild( kids ) );
-	// these types do not have associated type information
-	} else if ( auto newDeclStructDecl = dynamic_cast<ast::StructDecl *>( newDecl ) ) {
-		if ( newDeclStructDecl->body ) {
-			return new ast::CompoundLiteralExpr( location,
-				new ast::StructInstType( newDeclStructDecl ),
-				maybeMoveBuild( kids ) );
-		} else {
-			return new ast::CompoundLiteralExpr( location,
-				new ast::StructInstType( newDeclStructDecl->name ),
-				maybeMoveBuild( kids ) );
-		} // if
-	} else if ( auto newDeclUnionDecl = dynamic_cast<ast::UnionDecl *>( newDecl )  ) {
-		if ( newDeclUnionDecl->body ) {
-			return new ast::CompoundLiteralExpr( location,
-				new ast::UnionInstType( newDeclUnionDecl ),
-				maybeMoveBuild( kids ) );
-		} else {
-			return new ast::CompoundLiteralExpr( location,
-				new ast::UnionInstType( newDeclUnionDecl->name ),
-				maybeMoveBuild( kids ) );
-		} // if
-	} else if ( auto newDeclEnumDecl = dynamic_cast<ast::EnumDecl *>( newDecl )  ) {
-		if ( newDeclEnumDecl->body ) {
-			return new ast::CompoundLiteralExpr( location,
-				new ast::EnumInstType( newDeclEnumDecl ),
-				maybeMoveBuild( kids ) );
-		} else {
-			return new ast::CompoundLiteralExpr( location,
-				new ast::EnumInstType( newDeclEnumDecl->name ),
-				maybeMoveBuild( kids ) );
-		} // if
-	} else {
-		assert( false );
-	} // if
-} // build_compoundLiteral
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: src/Parser/ExpressionNode.cpp
===================================================================
--- src/Parser/ExpressionNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/ExpressionNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,784 @@
+//
+// 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.
+//
+// ExpressionNode.cpp --
+//
+// Author           : Peter A. Buhr
+// Created On       : Sat May 16 13:17:07 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Dec 14 18:57:07 2023
+// Update Count     : 1087
+//
+
+#include "ExpressionNode.hpp"
+
+#include <cassert>                 // for assert
+#include <stdio.h>                 // for sscanf, size_t
+#include <climits>                 // for LLONG_MAX, LONG_MAX, INT_MAX, UINT...
+#include <list>                    // for list
+#include <sstream>                 // for basic_istream::operator>>, basic_i...
+#include <string>                  // for string, operator+, operator==
+
+#include "AST/BasicKind.hpp"       // for BasicKind
+#include "AST/Expr.hpp"            // for NameExpr
+#include "AST/Type.hpp"            // for Type, LengthFlag, DimentionFlag
+#include "Common/SemanticError.hpp"// for SemanticError
+#include "Common/Utility.hpp"      // for maybeMoveBuild, maybeBuild, CodeLo...
+#include "DeclarationNode.hpp"     // for DeclarationNode
+#include "InitializerNode.hpp"     // for InitializerNode
+#include "TypeData.hpp"            // for addType, build_basic_type, build_c...
+#include "ParserUtility.hpp"       // for notZeroExpr
+
+using namespace std;
+
+//##############################################################################
+
+// Difficult to separate extra parts of constants during lexing because actions are not allow in the middle of patterns:
+//
+//		prefix action constant action suffix
+//
+// Alternatively, breaking a pattern using BEGIN does not work if the following pattern can be empty:
+//
+//		constant BEGIN CONT ...
+//		<CONT>(...)? BEGIN 0 ... // possible empty suffix
+//
+// because the CONT rule is NOT triggered if the pattern is empty. Hence, constants are reparsed here to determine their
+// type.
+
+// static inline bool checkH( char c ) { return c == 'h' || c == 'H'; }
+// static inline bool checkZ( char c ) { return c == 'z' || c == 'Z'; }
+// static inline bool checkU( char c ) { return c == 'u' || c == 'U'; }
+static inline bool checkF( char c ) { return c == 'f' || c == 'F'; }
+static inline bool checkD( char c ) { return c == 'd' || c == 'D'; }
+static inline bool checkF80( char c ) { return c == 'w' || c == 'W'; }
+static inline bool checkF128( char c ) { return c == 'q' || c == 'Q'; }
+static inline bool checkL( char c ) { return c == 'l' || c == 'L'; }
+static inline bool checkI( char c ) { return c == 'i' || c == 'I'; }
+static inline bool checkB( char c ) { return c == 'b' || c == 'B'; }
+static inline bool checkX( char c ) { return c == 'x' || c == 'X'; }
+// static inline bool checkN( char c ) { return c == 'n' || c == 'N'; }
+
+void lnthSuffix( string & str, int & type, int & ltype ) {
+	// 'u' can appear before or after length suffix
+	string::size_type posn = str.find_last_of( "lL" );
+
+	if ( posn == string::npos ) return;					// no suffix
+	size_t end = str.length() - 1;
+	if ( posn == end ) { type = 3; return; }			// no length after 'l' => long
+
+	string::size_type next = posn + 1;					// advance to length
+	if ( str[next] == '3' ) {							// 32
+		type = ltype = 2;
+	} else if ( str[next] == '6' ) {					// 64
+		type = ltype = 3;
+	} else if ( str[next] == '8' ) {					// 8
+		type = ltype = 1;
+	} else if ( str[next] == '1' ) {
+		if ( str[next + 1] == '6' ) {					// 16
+			type = ltype = 0;
+		} else {										// 128
+			type = 5; ltype = 6;
+		} // if
+	} // if
+
+	char fix = '\0';
+	if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ?
+	str.erase( posn );									// remove length suffix and possibly uU
+	if ( type == 5 ) {									// L128 does not need uU
+		end = str.length() - 1;
+		if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove
+	} else if ( fix != '\0' ) str += fix;				// put 'uU' back if removed
+} // lnthSuffix
+
+void valueToType( unsigned long long int & v, bool dec, int & type, bool & Unsigned ) {
+	// use value to determine type
+	if ( v <= INT_MAX ) {								// signed int
+		type = 2;
+	} else if ( v <= UINT_MAX && ! dec ) {				// unsigned int
+		type = 2;
+		Unsigned = true;								// unsigned
+	} else if ( v <= LONG_MAX ) {						// signed long int
+		type = 3;
+	} else if ( v <= ULONG_MAX && ( ! dec || LONG_MAX == LLONG_MAX ) ) { // signed long int
+		type = 3;
+		Unsigned = true;								// unsigned long int
+	} else if ( v <= LLONG_MAX ) {						// signed long long int
+		type = 4;
+	} else {											// unsigned long long int
+		type = 4;
+		Unsigned = true;								// unsigned long long int
+	} // if
+} // valueToType
+
+static void scanbin( string & str, unsigned long long int & v ) {
+	v = 0;
+	size_t last = str.length() - 1;						// last subscript of constant
+	for ( unsigned int i = 2;; ) {						// ignore prefix
+		if ( str[i] == '1' ) v |= 1;
+		i += 1;
+		if ( i == last - 1 || (str[i] != '0' && str[i] != '1') ) break;
+		v <<= 1;
+	} // for
+} // scanbin
+
+ast::Expr * build_constantInteger(
+		const CodeLocation & location, string & str ) {
+	static const ast::BasicKind kind[2][6] = {
+		// short (h) must be before char (hh) because shorter type has the longer suffix
+		{ ast::BasicKind::ShortSignedInt, ast::BasicKind::SignedChar, ast::BasicKind::SignedInt, ast::BasicKind::LongSignedInt, ast::BasicKind::LongLongSignedInt, /* BasicKind::SignedInt128 */ ast::BasicKind::LongLongSignedInt, },
+		{ ast::BasicKind::ShortUnsignedInt, ast::BasicKind::UnsignedChar, ast::BasicKind::UnsignedInt, ast::BasicKind::LongUnsignedInt, ast::BasicKind::LongLongUnsignedInt, /* BasicKind::UnsignedInt128 */ ast::BasicKind::LongLongUnsignedInt, },
+	};
+
+	static const char * lnthsInt[2][6] = {
+		{ "int16_t",  "int8_t",  "int32_t",  "int64_t",  "size_t",  "uintptr_t", },
+		{ "uint16_t", "uint8_t", "uint32_t", "uint64_t", "size_t",  "uintptr_t", },
+	}; // lnthsInt
+
+	string str2( "0x0" );
+	unsigned long long int v, v2 = 0;					// converted integral value
+	ast::Expr * ret, * ret2;
+
+	int type = -1;										// 0 => short, 1 => char, 2 => int, 3 => long int, 4 => long long int, 5 => int128
+	int ltype = -1;										// 0 => 16 bits, 1 => 8 bits, 2 => 32 bits, 3 => 64 bits, 4 => size_t, 5 => intptr, 6 => pointer
+	bool dec = true, Unsigned = false;					// decimal, unsigned constant
+
+	// special constants
+	if ( str == "0" ) {
+		ret = new ast::ConstantExpr( location, new ast::ZeroType(), str, 0 );
+		goto CLEANUP;
+	} // if
+	if ( str == "1" ) {
+		ret = new ast::ConstantExpr( location, new ast::OneType(), str, 1 );
+		goto CLEANUP;
+	} // if
+
+	// 'u' can appear before or after length suffix
+	if ( str.find_last_of( "uU" ) != string::npos ) Unsigned = true;
+
+	if ( isdigit( str[str.length() - 1] ) ) {			// no suffix ?
+		lnthSuffix( str, type, ltype );					// could have length suffix
+	} else {
+		// At least one digit in integer constant, so safe to backup while looking for suffix.
+		// This declaration and the comma expressions in the conditions mimic
+		// the declare and check pattern allowed in later compiler versions.
+		// (Only some early compilers/C++ standards do not support it.)
+		string::size_type posn;
+		// pointer value
+		if ( posn = str.find_last_of( "pP" ), posn != string::npos ) {
+			ltype = 5; str.erase( posn, 1 );
+		// size_t
+		} else if ( posn = str.find_last_of( "zZ" ), posn != string::npos ) {
+			Unsigned = true; type = 2; ltype = 4; str.erase( posn, 1 );
+		// signed char
+		} else if ( posn = str.rfind( "hh" ), posn != string::npos ) {
+			type = 1; str.erase( posn, 2 );
+		// signed char
+		} else if ( posn = str.rfind( "HH" ), posn != string::npos ) {
+			type = 1; str.erase( posn, 2 );
+		// short
+		} else if ( posn = str.find_last_of( "hH" ), posn != string::npos ) {
+			type = 0; str.erase( posn, 1 );
+		// int (natural number)
+		} else if ( posn = str.find_last_of( "nN" ), posn != string::npos ) {
+			type = 2; str.erase( posn, 1 );
+		} else if ( str.rfind( "ll" ) != string::npos || str.rfind( "LL" ) != string::npos ) {
+			type = 4;
+		} else {
+			lnthSuffix( str, type, ltype );
+		} // if
+	} // if
+
+	// Cannot be just "0"/"1"; sscanf stops at the suffix, if any; value goes over the wall => always generate
+
+#if ! defined(__SIZEOF_INT128__)
+	if ( type == 5 ) SemanticError( yylloc, "int128 constant is not supported on this target \"%s\"", str.c_str() );
+#endif // ! __SIZEOF_INT128__
+
+	if ( str[0] == '0' ) {								// radix character ?
+		dec = false;
+		if ( checkX( str[1] ) ) {						// hex constant ?
+			if ( type < 5 ) {							// not L128 ?
+				sscanf( (char *)str.c_str(), "%llx", &v );
+#if defined(__SIZEOF_INT128__)
+			} else {									// hex int128 constant
+				unsigned int len = str.length();
+				if ( len > (2 + 16 + 16) ) SemanticError( yylloc, "128-bit hexadecimal constant to large \"%s\"", str.c_str() );
+				// hex digits < 2^64
+				if ( len > (2 + 16) ) {
+					str2 = "0x" + str.substr( len - 16 );
+					sscanf( (char *)str2.c_str(), "%llx", &v2 );
+					str = str.substr( 0, len - 16 );
+				} // if
+				sscanf( (char *)str.c_str(), "%llx", &v );
+#endif // __SIZEOF_INT128__
+			} // if
+			//printf( "%llx %llu\n", v, v );
+		} else if ( checkB( str[1] ) ) {				// binary constant ?
+#if defined(__SIZEOF_INT128__)
+			unsigned int len = str.length();
+			if ( type == 5 && len > 2 + 64 ) {
+				if ( len > 2 + 64 + 64 ) SemanticError( yylloc, "128-bit binary constant to large \"%s\".", str.c_str() );
+				str2 = "0b" + str.substr( len - 64 );
+				str = str.substr( 0, len - 64 );
+				scanbin( str2, v2 );
+			} // if
+#endif // __SIZEOF_INT128__
+			scanbin( str, v );
+			//printf( "%#llx %llu\n", v, v );
+		} else {										// octal constant
+			if ( type < 5 ) {							// not L128 ?
+				sscanf( (char *)str.c_str(), "%llo", &v );
+#if defined(__SIZEOF_INT128__)
+			} else {									// octal int128 constant
+				unsigned int len = str.length();
+				if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large \"%s\"", str.c_str() );
+				char buf[32];
+				if ( len <= 1 + 21 ) {					// value < 21 octal digitis
+					sscanf( (char *)str.c_str(), "%llo", &v );
+				} else {
+					sscanf( &str[len - 21], "%llo", &v );
+					__int128 val = v;					// accumulate bits
+					str[len - 21] ='\0';				// shorten string
+					sscanf( &str[len == 43 ? 1 : 0], "%llo", &v );
+					val |= (__int128)v << 63;			// store bits
+					if ( len == 1 + 43 ) {				// most significant 2 bits ?
+						str[2] = '\0';					// shorten string
+						sscanf( &str[1], "%llo", &v );	// process most significant 2 bits
+						val |= (__int128)v << 126;		// store bits
+					} // if
+					v = val >> 64; v2 = (uint64_t)val;	// replace octal constant with 2 hex constants
+					sprintf( buf, "%#llx", v2 );
+					str2 = buf;
+				} // if
+				sprintf( buf, "%#llx", v );
+				str = buf;
+#endif // __SIZEOF_INT128__
+			} // if
+			//printf( "%#llo %llu\n", v, v );
+		} // if
+	} else {											// decimal constant ?
+		if ( type < 5 ) {								// not L128 ?
+			sscanf( (char *)str.c_str(), "%llu", &v );
+#if defined(__SIZEOF_INT128__)
+		} else {										// decimal int128 constant
+			#define P10_UINT64 10'000'000'000'000'000'000ULL // 19 zeroes
+			unsigned int len = str.length();
+			if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") )
+				SemanticError( yylloc, "128-bit decimal constant to large \"%s\".", str.c_str() );
+			char buf[32];
+			if ( len <= 19 ) {							// value < 19 decimal digitis
+				sscanf( (char *)str.c_str(), "%llu", &v );
+			} else {
+				sscanf( &str[len - 19], "%llu", &v );
+				__int128 val = v;						// accumulate bits
+				str[len - 19] ='\0';					// shorten string
+				sscanf( &str[len == 39 ? 1 : 0], "%llu", &v );
+				val += (__int128)v * (__int128)P10_UINT64; // store bits
+				if ( len == 39 ) {						// most significant 2 bits ?
+					str[1] = '\0';						// shorten string
+					sscanf( &str[0], "%llu", &v );		// process most significant 2 bits
+					val += (__int128)v * (__int128)P10_UINT64 * (__int128)P10_UINT64; // store bits
+				} // if
+				v = val >> 64; v2 = (uint64_t)val;		// replace decimal constant with 2 hex constants
+				sprintf( buf, "%#llx", v2 );
+				str2 = buf;
+			} // if
+			sprintf( buf, "%#llx", v );
+			str = buf;
+#endif // __SIZEOF_INT128__
+		} // if
+		//printf( "%llu\n", v );
+	} // if
+
+	if ( type == -1 ) {									// no suffix => determine type from value size
+		valueToType( v, dec, type, Unsigned );
+	} // if
+	/* printf( "%s %llo %s %llo\n", str.c_str(), v, str2.c_str(), v2 ); */
+
+	//if ( !( 0 <= type && type <= 6 ) ) { printf( "%s %lu %d %s\n", fred.c_str(), fred.length(), type, str.c_str() ); }
+	assert( 0 <= type && type <= 6 );
+
+	// Constant type is correct for overload resolving.
+	ret = new ast::ConstantExpr( location,
+		new ast::BasicType( kind[Unsigned][type] ), str, v );
+	if ( Unsigned && type < 2 ) {						// hh or h, less than int ?
+		// int i = -1uh => 65535 not -1, so cast is necessary for unsigned, which unfortunately eliminates warnings for large values.
+		ret = new ast::CastExpr( location,
+			ret,
+			new ast::BasicType( kind[Unsigned][type] ),
+			ast::ExplicitCast );
+	} else if ( ltype != -1 ) {							// explicit length ?
+		if ( ltype == 6 ) {								// int128, (int128)constant
+			ret2 = new ast::ConstantExpr( location,
+				new ast::BasicType( ast::BasicKind::LongLongSignedInt ),
+				str2,
+				v2 );
+			ret = build_compoundLiteral( location,
+				DeclarationNode::newFromTypeData(
+					addType(
+						build_basic_type( TypeData::Int128 ),
+						build_signedness( TypeData::Unsigned ) ) ),
+				new InitializerNode(
+					(new InitializerNode( new ExpressionNode( v2 == 0 ? ret2 : ret ) ))->set_last( new InitializerNode( new ExpressionNode( v2 == 0 ? ret : ret2 ) ) ), true )
+			);
+		} else {										// explicit length, (length_type)constant
+			ret = new ast::CastExpr( location,
+				ret,
+				new ast::TypeInstType( lnthsInt[Unsigned][ltype], ast::TypeDecl::Dtype ),
+				ast::ExplicitCast );
+			if ( ltype == 5 ) {							// pointer, intptr( (uintptr_t)constant )
+				ret = build_func( location,
+					new ExpressionNode(
+						build_varref( location, new string( "intptr" ) ) ),
+					new ExpressionNode( ret ) );
+			} // if
+		} // if
+	} // if
+
+  CLEANUP: ;
+	delete &str;										// created by lex
+	return ret;
+} // build_constantInteger
+
+
+static inline void checkFnxFloat( string & str, size_t last, bool & explnth, int & type ) {
+	string::size_type posn;
+	// floating-point constant has minimum of 2 characters, 1. or .1, so safe to look ahead
+	if ( str[1] == 'x' ) {								// hex ?
+		posn = str.find_last_of( "pP" );				// back for exponent (must have)
+		posn = str.find_first_of( "fF", posn + 1 );		// forward for size (fF allowed in hex constant)
+	} else {
+		posn = str.find_last_of( "fF" );				// back for size (fF not allowed)
+	} // if
+  if ( posn == string::npos ) return;
+	explnth = true;
+	posn += 1;											// advance to size
+	if ( str[posn] == '3' ) {							// 32
+		if ( str[last] != 'x' ) type = 6;
+		else type = 7;
+	} else if ( str[posn] == '6' ) {					// 64
+		if ( str[last] != 'x' ) type = 8;
+		else type = 9;
+	} else if ( str[posn] == '8' ) {					// 80
+		type = 3;
+	} else if ( str[posn] == '1' ) {					// 16/128
+		if ( str[posn + 1] == '6' ) {					// 16
+			type = 5;
+		} else {										// 128
+			if ( str[last] != 'x' ) type = 10;
+			else type = 11;
+		} // if
+	} else {
+		assertf( false, "internal error, bad floating point length %s", str.c_str() );
+	} // if
+} // checkFnxFloat
+
+
+ast::Expr * build_constantFloat(
+		const CodeLocation & location, string & str ) {
+	static const ast::BasicKind kind[2][12] = {
+		{ ast::BasicKind::Float, ast::BasicKind::Double, ast::BasicKind::LongDouble, ast::BasicKind::uuFloat80, ast::BasicKind::uuFloat128, ast::BasicKind::uFloat16, ast::BasicKind::uFloat32, ast::BasicKind::uFloat32x, ast::BasicKind::uFloat64, ast::BasicKind::uFloat64x, ast::BasicKind::uFloat128, ast::BasicKind::uFloat128x },
+		{ ast::BasicKind::FloatComplex, ast::BasicKind::DoubleComplex, ast::BasicKind::LongDoubleComplex, ast::BasicKind::NUMBER_OF_BASIC_TYPES, ast::BasicKind::NUMBER_OF_BASIC_TYPES, ast::BasicKind::uFloat16Complex, ast::BasicKind::uFloat32Complex, ast::BasicKind::uFloat32xComplex, ast::BasicKind::uFloat64Complex, ast::BasicKind::uFloat64xComplex, ast::BasicKind::uFloat128Complex, ast::BasicKind::uFloat128xComplex },
+	};
+
+	// floating-point constant has minimum of 2 characters 1. or .1
+	size_t last = str.length() - 1;
+	double v;
+	int type;											// 0 => float, 1 => double, 3 => long double, ...
+	bool complx = false;								// real, complex
+	bool explnth = false;								// explicit literal length
+
+	sscanf( str.c_str(), "%lg", &v );
+
+	if ( checkI( str[last] ) ) {						// imaginary ?
+		complx = true;
+		last -= 1;										// backup one character
+	} // if
+
+	if ( checkF( str[last] ) ) {						// float ?
+		type = 0;
+	} else if ( checkD( str[last] ) ) {					// double ?
+		type = 1;
+	} else if ( checkL( str[last] ) ) {					// long double ?
+		type = 2;
+	} else if ( checkF80( str[last] ) ) {				// __float80 ?
+		type = 3;
+	} else if ( checkF128( str[last] ) ) {				// __float128 ?
+		type = 4;
+	} else {
+		type = 1;										// double (default if no suffix)
+		checkFnxFloat( str, last, explnth, type );
+	} // if
+
+	if ( ! complx && checkI( str[last - 1] ) ) {		// imaginary ?
+		complx = true;
+	} // if
+
+	assert( 0 <= type && type < 12 );
+	ast::Expr * ret = new ast::ConstantExpr( location,
+		new ast::BasicType( kind[complx][type] ),
+		str,
+		v );
+	// explicit length ?
+	if ( explnth ) {
+		ret = new ast::CastExpr( location,
+			ret,
+			new ast::BasicType( kind[complx][type] ),
+			ast::ExplicitCast );
+	} // if
+
+	delete &str;										// created by lex
+	return ret;
+} // build_constantFloat
+
+static void sepString( string & str, string & units, char delimit ) {
+	string::size_type posn = str.find_last_of( delimit ) + 1;
+	if ( posn != str.length() ) {
+		units = "?" + str.substr( posn );				// extract units
+		str.erase( posn );								// remove units
+	} // if
+} // sepString
+
+ast::Expr * build_constantChar( const CodeLocation & location, string & str ) {
+	string units;										// units
+	sepString( str, units, '\'' );						// separate constant from units
+
+	ast::Expr * ret = new ast::ConstantExpr( location,
+		new ast::BasicType( ast::BasicKind::Char ),
+		str,
+		(unsigned long long int)(unsigned char)str[1] );
+	if ( units.length() != 0 ) {
+		ret = new ast::UntypedExpr( location,
+			new ast::NameExpr( location, units ),
+			{ ret } );
+	} // if
+
+	delete &str;										// created by lex
+	return ret;
+} // build_constantChar
+
+ast::Expr * build_constantStr(
+		const CodeLocation & location,
+		string & str ) {
+	assert( str.length() > 0 );
+	string units;										// units
+	sepString( str, units, '"' );						// separate constant from units
+
+	ast::Type * strtype;
+	switch ( str[0] ) {									// str has >= 2 characters, i.e, null string "" => safe to look at subscripts 0/1
+	case 'u':
+		if ( str[1] == '8' ) goto Default;				// utf-8 characters => array of char
+		// lookup type of associated typedef
+		strtype = new ast::TypeInstType( "char16_t", ast::TypeDecl::Dtype );
+		break;
+	case 'U':
+		strtype = new ast::TypeInstType( "char32_t", ast::TypeDecl::Dtype );
+		break;
+	case 'L':
+		strtype = new ast::TypeInstType( "wchar_t", ast::TypeDecl::Dtype );
+		break;
+	Default:											// char default string type
+	default:
+		strtype = new ast::BasicType( ast::BasicKind::Char );
+	} // switch
+	ast::ArrayType * at = new ast::ArrayType(
+		strtype,
+		// Length is adjusted: +1 for '\0' and -2 for '"'
+		ast::ConstantExpr::from_ulong( location, str.size() + 1 - 2 ),
+		ast::FixedLen,
+		ast::DynamicDim );
+	ast::Expr * ret = new ast::ConstantExpr( location, at, str, std::nullopt );
+	if ( units.length() != 0 ) {
+		ret = new ast::UntypedExpr( location,
+			new ast::NameExpr( location, units ),
+			{ ret } );
+	} // if
+
+	delete &str;										// created by lex
+	return ret;
+} // build_constantStr
+
+ast::Expr * build_field_name_FLOATING_FRACTIONconstant(
+		const CodeLocation & location, const string & str ) {
+	if ( str.find_first_not_of( "0123456789", 1 ) != string::npos ) SemanticError( yylloc, "invalid tuple index \"%s\".", str.c_str() );
+	ast::Expr * ret = build_constantInteger( location,
+		*new string( str.substr(1) ) );
+	delete &str;
+	return ret;
+} // build_field_name_FLOATING_FRACTIONconstant
+
+ast::Expr * build_field_name_FLOATING_DECIMALconstant(
+		const CodeLocation & location, const string & str ) {
+	if ( str[str.size() - 1] != '.' ) SemanticError( yylloc, "invalid tuple index \"%s\".", str.c_str() );
+	ast::Expr * ret = build_constantInteger(
+		location, *new string( str.substr( 0, str.size()-1 ) ) );
+	delete &str;
+	return ret;
+} // build_field_name_FLOATING_DECIMALconstant
+
+ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation & location,
+		const string & str ) {
+	// str is of the form A.B -> separate at the . and return member expression
+	int a, b;
+	char dot;
+	stringstream ss( str );
+	ss >> a >> dot >> b;
+	auto ret = new ast::UntypedMemberExpr( location,
+		ast::ConstantExpr::from_int( location, b ),
+		ast::ConstantExpr::from_int( location, a )
+	);
+	delete &str;
+	return ret;
+} // build_field_name_FLOATINGconstant
+
+ast::Expr * make_field_name_fraction_constants( const CodeLocation & location,
+		ast::Expr * fieldName,
+		ast::Expr * fracts ) {
+	if ( nullptr == fracts ) {
+		return fieldName;
+	} else if ( auto memberExpr = dynamic_cast<ast::UntypedMemberExpr *>( fracts ) ) {
+		memberExpr->member = make_field_name_fraction_constants( location,
+			fieldName,
+			ast::mutate( memberExpr->aggregate.get() ) );
+		return memberExpr;
+	} else {
+		return new ast::UntypedMemberExpr( location, fracts, fieldName );
+	} // if
+} // make_field_name_fraction_constants
+
+ast::Expr * build_field_name_fraction_constants( const CodeLocation & location,
+		ast::Expr * fieldName,
+		ExpressionNode * fracts ) {
+	return make_field_name_fraction_constants( location, fieldName, maybeMoveBuild( fracts ) );
+} // build_field_name_fraction_constants
+
+ast::NameExpr * build_varref( const CodeLocation & location,
+		const string * name ) {
+	ast::NameExpr * expr = new ast::NameExpr( location, *name );
+	delete name;
+	return expr;
+} // build_varref
+
+ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location,
+		const DeclarationNode * decl_node,
+		const ast::NameExpr * name ) {
+	ast::Decl * newDecl = maybeBuild( decl_node );
+	if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) {
+		if ( const ast::Type * t = newDeclWithType->get_type() ) {
+			if ( auto typeInst = dynamic_cast<const ast::TypeInstType *>( t ) ) {
+				newDecl = new ast::EnumDecl( location, typeInst->name );
+			}
+		}
+	}
+	return new ast::QualifiedNameExpr( location, newDecl, name->name );
+}
+
+ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation & location,
+		const ast::EnumDecl * decl,
+		const ast::NameExpr * name ) {
+	return new ast::QualifiedNameExpr( location, decl, name->name );
+}
+
+ast::DimensionExpr * build_dimensionref( const CodeLocation & location,
+		const string * name ) {
+	ast::DimensionExpr * expr = new ast::DimensionExpr( location, *name );
+	delete name;
+	return expr;
+} // build_varref
+
+// TODO: get rid of this and OperKinds and reuse code from OperatorTable
+static const char * OperName[] = {						// must harmonize with OperKinds
+	// diadic
+	"SizeOf", "AlignOf", "OffsetOf", "?+?", "?-?", "?\\?", "?*?", "?/?", "?%?", "||", "&&",
+	"?|?", "?&?", "?^?", "Cast", "?<<?", "?>>?", "?<?", "?>?", "?<=?", "?>=?", "?==?", "?!=?",
+	"?=?", "?@=?", "?\\=?", "?*=?", "?/=?", "?%=?", "?+=?", "?-=?", "?<<=?", "?>>=?", "?&=?", "?^=?", "?|=?",
+	"?[?]", "...",
+	// monadic
+	"+?", "-?", "AddressOf", "*?", "!?", "~?", "++?", "?++", "--?", "?--",
+}; // OperName
+
+ast::Expr * build_cast( const CodeLocation & location,
+		DeclarationNode * decl_node,
+		ExpressionNode * expr_node,
+		ast::CastExpr::CastKind kind ) {
+	ast::Type * targetType = maybeMoveBuildType( decl_node );
+	if ( dynamic_cast<ast::VoidType *>( targetType ) ) {
+		delete targetType;
+		return new ast::CastExpr( location,
+			maybeMoveBuild( expr_node ),
+			ast::ExplicitCast, kind );
+	} else {
+		return new ast::CastExpr( location,
+			maybeMoveBuild( expr_node ),
+			targetType,
+			ast::ExplicitCast, kind );
+	} // if
+} // build_cast
+
+ast::Expr * build_keyword_cast( const CodeLocation & location,
+		ast::AggregateDecl::Aggregate target,
+		ExpressionNode * expr_node ) {
+	return new ast::KeywordCastExpr( location,
+		maybeMoveBuild( expr_node ),
+		target
+	);
+}
+
+ast::Expr * build_virtual_cast( const CodeLocation & location,
+		DeclarationNode * decl_node,
+		ExpressionNode * expr_node ) {
+	return new ast::VirtualCastExpr( location,
+		maybeMoveBuild( expr_node ),
+		maybeMoveBuildType( decl_node )
+	);
+} // build_virtual_cast
+
+ast::Expr * build_fieldSel( const CodeLocation & location,
+		ExpressionNode * expr_node,
+		ast::Expr * member ) {
+	return new ast::UntypedMemberExpr( location,
+		member,
+		maybeMoveBuild( expr_node )
+	);
+} // build_fieldSel
+
+ast::Expr * build_pfieldSel( const CodeLocation & location,
+		ExpressionNode * expr_node,
+		ast::Expr * member ) {
+	auto deref = new ast::UntypedExpr( location,
+		new ast::NameExpr( location, "*?" )
+	);
+	deref->location = expr_node->location;
+	deref->args.push_back( maybeMoveBuild( expr_node ) );
+	auto ret = new ast::UntypedMemberExpr( location, member, deref );
+	return ret;
+} // build_pfieldSel
+
+ast::Expr * build_offsetOf( const CodeLocation & location,
+		DeclarationNode * decl_node,
+		ast::NameExpr * member ) {
+	ast::Expr * ret = new ast::UntypedOffsetofExpr( location,
+		maybeMoveBuildType( decl_node ),
+		member->name
+	);
+	ret->result = new ast::BasicType( ast::BasicKind::LongUnsignedInt );
+	delete member;
+	return ret;
+} // build_offsetOf
+
+ast::Expr * build_and_or( const CodeLocation & location,
+		ExpressionNode * expr_node1,
+		ExpressionNode * expr_node2,
+		ast::LogicalFlag flag ) {
+	return new ast::LogicalExpr( location,
+		maybeMoveBuild( expr_node1 ),
+		maybeMoveBuild( expr_node2 ),
+		flag
+	);
+} // build_and_or
+
+ast::Expr * build_unary_val( const CodeLocation & location,
+		OperKinds op,
+		ExpressionNode * expr_node ) {
+	std::vector<ast::ptr<ast::Expr>> args;
+	args.push_back( maybeMoveBuild( expr_node ) );
+	return new ast::UntypedExpr( location,
+		new ast::NameExpr( location, OperName[ (int)op ] ),
+		std::move( args )
+	);
+} // build_unary_val
+
+ast::Expr * build_binary_val( const CodeLocation & location,
+		OperKinds op,
+		ExpressionNode * expr_node1,
+		ExpressionNode * expr_node2 ) {
+	std::vector<ast::ptr<ast::Expr>> args;
+	args.push_back( maybeMoveBuild( expr_node1 ) );
+	args.push_back( maybeMoveBuild( expr_node2 ) );
+	return new ast::UntypedExpr( location,
+		new ast::NameExpr( location, OperName[ (int)op ] ),
+		std::move( args )
+	);
+} // build_binary_val
+
+ast::Expr * build_cond( const CodeLocation & location,
+		ExpressionNode * expr_node1,
+		ExpressionNode * expr_node2,
+		ExpressionNode * expr_node3 ) {
+	return new ast::ConditionalExpr( location,
+		maybeMoveBuild( expr_node1 ),
+		maybeMoveBuild( expr_node2 ),
+		maybeMoveBuild( expr_node3 )
+	);
+} // build_cond
+
+ast::Expr * build_tuple( const CodeLocation & location,
+		ExpressionNode * expr_node ) {
+	std::vector<ast::ptr<ast::Expr>> exprs;
+	buildMoveList( expr_node, exprs );
+	return new ast::UntypedTupleExpr( location, std::move( exprs ) );
+} // build_tuple
+
+ast::Expr * build_func( const CodeLocation & location,
+		ExpressionNode * function,
+		ExpressionNode * expr_node ) {
+	std::vector<ast::ptr<ast::Expr>> args;
+	buildMoveList( expr_node, args );
+	return new ast::UntypedExpr( location,
+		maybeMoveBuild( function ),
+		std::move( args )
+	);
+} // build_func
+
+ast::Expr * build_compoundLiteral( const CodeLocation & location,
+		DeclarationNode * decl_node,
+		InitializerNode * kids ) {
+	// compound literal type
+	ast::Decl * newDecl = maybeBuild( decl_node );
+	// non-sue compound-literal type
+	if ( ast::DeclWithType * newDeclWithType = dynamic_cast<ast::DeclWithType *>( newDecl ) ) {
+		return new ast::CompoundLiteralExpr( location,
+			newDeclWithType->get_type(),
+			maybeMoveBuild( kids ) );
+	// these types do not have associated type information
+	} else if ( auto newDeclStructDecl = dynamic_cast<ast::StructDecl *>( newDecl ) ) {
+		if ( newDeclStructDecl->body ) {
+			return new ast::CompoundLiteralExpr( location,
+				new ast::StructInstType( newDeclStructDecl ),
+				maybeMoveBuild( kids ) );
+		} else {
+			return new ast::CompoundLiteralExpr( location,
+				new ast::StructInstType( newDeclStructDecl->name ),
+				maybeMoveBuild( kids ) );
+		} // if
+	} else if ( auto newDeclUnionDecl = dynamic_cast<ast::UnionDecl *>( newDecl )  ) {
+		if ( newDeclUnionDecl->body ) {
+			return new ast::CompoundLiteralExpr( location,
+				new ast::UnionInstType( newDeclUnionDecl ),
+				maybeMoveBuild( kids ) );
+		} else {
+			return new ast::CompoundLiteralExpr( location,
+				new ast::UnionInstType( newDeclUnionDecl->name ),
+				maybeMoveBuild( kids ) );
+		} // if
+	} else if ( auto newDeclEnumDecl = dynamic_cast<ast::EnumDecl *>( newDecl )  ) {
+		if ( newDeclEnumDecl->body ) {
+			return new ast::CompoundLiteralExpr( location,
+				new ast::EnumInstType( newDeclEnumDecl ),
+				maybeMoveBuild( kids ) );
+		} else {
+			return new ast::CompoundLiteralExpr( location,
+				new ast::EnumInstType( newDeclEnumDecl->name ),
+				maybeMoveBuild( kids ) );
+		} // if
+	} else {
+		assert( false );
+	} // if
+} // build_compoundLiteral
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: src/Parser/ExpressionNode.h
===================================================================
--- src/Parser/ExpressionNode.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,86 +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.
-//
-// ExpressionNode.h --
-//
-// Author           : Andrew Beach
-// Created On       : Wed Apr  5 11:34:00 2023
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Apr  5 11:50:00 2023
-// Update Count     : 0
-//
-
-#pragma once
-
-#include "ParseNode.h"
-
-struct InitializerNode;
-
-struct ExpressionNode final : public ParseList<ExpressionNode> {
-	ExpressionNode( ast::Expr * expr = nullptr ) : expr( expr ) {}
-	virtual ~ExpressionNode() {}
-	virtual ExpressionNode * clone() const override {
-		if ( nullptr == expr ) return nullptr;
-		ExpressionNode * node = new ExpressionNode( ast::shallowCopy( expr.get() ) );
-		node->next = maybeCopy( next );
-		return node;
-	}
-
-	bool get_extension() const { return extension; }
-	ExpressionNode * set_extension( bool exten ) { extension = exten; return this; }
-
-	virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
-		os << expr.get();
-	}
-	void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
-
-	template<typename T>
-	bool isExpressionType() const {  return nullptr != dynamic_cast<T>(expr.get()); }
-
-	ast::Expr * build() {
-		ast::Expr * node = expr.release();
-		node->set_extension( this->get_extension() );
-		node->location = this->location;
-		return node;
-	}
-
-	// Public because of lifetime implications (what lifetime implications?)
-	std::unique_ptr<ast::Expr> expr;
-private:
-	bool extension = false;
-}; // ExpressionNode
-
-// These 4 routines modify the string:
-ast::Expr * build_constantInteger( const CodeLocation &, std::string & );
-ast::Expr * build_constantFloat( const CodeLocation &, std::string & );
-ast::Expr * build_constantChar( const CodeLocation &, std::string & );
-ast::Expr * build_constantStr( const CodeLocation &, std::string & );
-ast::Expr * build_field_name_FLOATING_FRACTIONconstant( const CodeLocation &, const std::string & str );
-ast::Expr * build_field_name_FLOATING_DECIMALconstant( const CodeLocation &, const std::string & str );
-ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation &, const std::string & str );
-ast::Expr * build_field_name_fraction_constants( const CodeLocation &, ast::Expr * fieldName, ExpressionNode * fracts );
-
-ast::NameExpr * build_varref( const CodeLocation &, const std::string * name );
-ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const DeclarationNode * decl_node, const ast::NameExpr * name );
-ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const ast::EnumDecl * decl, const ast::NameExpr * name );
-ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name );
-
-ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node, ast::CastExpr::CastKind kind = ast::CastExpr::Default );
-ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node );
-ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
-ast::Expr * build_fieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
-ast::Expr * build_pfieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
-ast::Expr * build_offsetOf( const CodeLocation &, DeclarationNode * decl_node, ast::NameExpr * member );
-ast::Expr * build_and( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
-ast::Expr * build_and_or( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ast::LogicalFlag flag );
-ast::Expr * build_unary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node );
-ast::Expr * build_binary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
-ast::Expr * build_cond( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 );
-ast::Expr * build_tuple( const CodeLocation &, ExpressionNode * expr_node = nullptr );
-ast::Expr * build_func( const CodeLocation &, ExpressionNode * function, ExpressionNode * expr_node );
-ast::Expr * build_compoundLiteral( const CodeLocation &, DeclarationNode * decl_node, InitializerNode * kids );
-
-ast::Expr * build_enum_pos_expr( const CodeLocation &, ast::Expr * expr_node );
Index: src/Parser/ExpressionNode.hpp
===================================================================
--- src/Parser/ExpressionNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/ExpressionNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,86 @@
+//
+// 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.
+//
+// ExpressionNode.hpp --
+//
+// Author           : Andrew Beach
+// Created On       : Wed Apr  5 11:34:00 2023
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Apr  5 11:50:00 2023
+// Update Count     : 0
+//
+
+#pragma once
+
+#include "ParseNode.hpp"
+
+struct InitializerNode;
+
+struct ExpressionNode final : public ParseList<ExpressionNode> {
+	ExpressionNode( ast::Expr * expr = nullptr ) : expr( expr ) {}
+	virtual ~ExpressionNode() {}
+	virtual ExpressionNode * clone() const override {
+		if ( nullptr == expr ) return nullptr;
+		ExpressionNode * node = new ExpressionNode( ast::shallowCopy( expr.get() ) );
+		node->next = maybeCopy( next );
+		return node;
+	}
+
+	bool get_extension() const { return extension; }
+	ExpressionNode * set_extension( bool exten ) { extension = exten; return this; }
+
+	virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
+		os << expr.get();
+	}
+	void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
+
+	template<typename T>
+	bool isExpressionType() const {  return nullptr != dynamic_cast<T>(expr.get()); }
+
+	ast::Expr * build() {
+		ast::Expr * node = expr.release();
+		node->set_extension( this->get_extension() );
+		node->location = this->location;
+		return node;
+	}
+
+	// Public because of lifetime implications (what lifetime implications?)
+	std::unique_ptr<ast::Expr> expr;
+private:
+	bool extension = false;
+}; // ExpressionNode
+
+// These 4 routines modify the string:
+ast::Expr * build_constantInteger( const CodeLocation &, std::string & );
+ast::Expr * build_constantFloat( const CodeLocation &, std::string & );
+ast::Expr * build_constantChar( const CodeLocation &, std::string & );
+ast::Expr * build_constantStr( const CodeLocation &, std::string & );
+ast::Expr * build_field_name_FLOATING_FRACTIONconstant( const CodeLocation &, const std::string & str );
+ast::Expr * build_field_name_FLOATING_DECIMALconstant( const CodeLocation &, const std::string & str );
+ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation &, const std::string & str );
+ast::Expr * build_field_name_fraction_constants( const CodeLocation &, ast::Expr * fieldName, ExpressionNode * fracts );
+
+ast::NameExpr * build_varref( const CodeLocation &, const std::string * name );
+ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const DeclarationNode * decl_node, const ast::NameExpr * name );
+ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const ast::EnumDecl * decl, const ast::NameExpr * name );
+ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name );
+
+ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node, ast::CastExpr::CastKind kind = ast::CastExpr::Default );
+ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node );
+ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
+ast::Expr * build_fieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
+ast::Expr * build_pfieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
+ast::Expr * build_offsetOf( const CodeLocation &, DeclarationNode * decl_node, ast::NameExpr * member );
+ast::Expr * build_and( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
+ast::Expr * build_and_or( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ast::LogicalFlag flag );
+ast::Expr * build_unary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node );
+ast::Expr * build_binary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
+ast::Expr * build_cond( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 );
+ast::Expr * build_tuple( const CodeLocation &, ExpressionNode * expr_node = nullptr );
+ast::Expr * build_func( const CodeLocation &, ExpressionNode * function, ExpressionNode * expr_node );
+ast::Expr * build_compoundLiteral( const CodeLocation &, DeclarationNode * decl_node, InitializerNode * kids );
+
+ast::Expr * build_enum_pos_expr( const CodeLocation &, ast::Expr * expr_node );
Index: src/Parser/InitializerNode.cc
===================================================================
--- src/Parser/InitializerNode.cc	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,127 +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.
-//
-// InitializerNode.cc --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Sat May 16 13:20:24 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Apr  4 11:18:00 2023
-// Update Count     : 27
-//
-
-#include "InitializerNode.h"
-
-#include <iostream>                // for operator<<, ostream, basic_ostream
-#include <list>                    // for list
-#include <string>                  // for operator<<, string
-
-#include "AST/Expr.hpp"            // for Expr
-#include "AST/Init.hpp"            // for Designator, Init, ListInit, Sing...
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/utility.h"        // for maybeBuild
-#include "ExpressionNode.h"        // for ExpressionNode
-#include "DeclarationNode.h"       // for buildList
-
-using namespace std;
-
-static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) {
-	return maybeConstructed ? ast::MaybeConstruct : ast::NoConstruct;
-}
-
-InitializerNode::InitializerNode( ExpressionNode * _expr, bool aggrp, ExpressionNode * des )
-		: expr( _expr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ), isDelete( false ) {
-	if ( aggrp )
-		kids = next;
-
-	if ( kids )
-		set_last( nullptr );
-} // InitializerNode::InitializerNode
-
-InitializerNode::InitializerNode( InitializerNode * init, bool aggrp, ExpressionNode * des )
-		: expr( nullptr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ), isDelete( false ) {
-	if ( init )
-		set_last( init );
-
-	if ( aggrp )
-		kids = next;
-
-	if ( kids )
-		next = nullptr;
-} // InitializerNode::InitializerNode
-
-InitializerNode::InitializerNode( bool isDelete ) : expr( nullptr ), aggregate( false ), designator( nullptr ), kids( nullptr ), maybeConstructed( false ), isDelete( isDelete ) {}
-
-InitializerNode::~InitializerNode() {
-	delete expr;
-	delete designator;
-	delete kids;
-} // InitializerNode::~InitializerNode
-
-void InitializerNode::print( std::ostream &os, int indent ) const {
-	os << std::string( indent, ' ' ) << "Initializer expression" << std::endl;
-} // InitializerNode::print
-
-void InitializerNode::printOneLine( std::ostream &os ) const {
-	if ( ! aggregate ) {
-		if ( designator ) {
-			os << "designated by: (";
-			ExpressionNode *curdes = designator;
-			while ( curdes != nullptr) {
-				curdes->printOneLine(os);
-				curdes = curdes->next;
-				if ( curdes ) os << ", ";
-			} // while
-			os << ")";
-		} // if
-		if ( expr ) expr->printOneLine( os );
-	} else {  // It's an aggregate
-		os << "[--";
-		if ( next_init() != nullptr )
-			next_init()->printOneLine( os );
-		if (aggregate) os << "--]";
-	} // if
-
-	InitializerNode *moreInit;
-	if ( ( moreInit = next ) ) {
-		moreInit->printOneLine( os );
-	} // if
-} // InitializerNode::printOneLine
-
-ast::Init * InitializerNode::build() const {
-	assertf( ! isDelete, "Should not build delete stmt InitializerNode" );
-	if ( aggregate ) {
-		// steal designators from children
-		std::vector<ast::ptr<ast::Designation>> designlist;
-		InitializerNode * child = next_init();
-		for ( ; child != nullptr ; child = child->next ) {
-			std::deque<ast::ptr<ast::Expr>> desList;
-			buildList( child->designator, desList );
-			designlist.push_back(
-				new ast::Designation( location, std::move( desList ) ) );
-		} // for
-		std::vector<ast::ptr<ast::Init>> initlist;
-		buildList( next_init(), initlist );
-		return new ast::ListInit( location,
-			std::move( initlist ),
-			std::move( designlist ),
-			toConstructFlag( maybeConstructed )
-		);
-	} else if ( get_expression() ) {
-		assertf( get_expression()->expr, "The expression of initializer must have value" );
-		return new ast::SingleInit( location,
-			maybeBuild( get_expression() ),
-			toConstructFlag( maybeConstructed )
-		);
-	} // if
-	return nullptr;
-} // InitializerNode::build
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/InitializerNode.cpp
===================================================================
--- src/Parser/InitializerNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/InitializerNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,127 @@
+//
+// 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.
+//
+// InitializerNode.cpp --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Sat May 16 13:20:24 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Apr  4 11:18:00 2023
+// Update Count     : 27
+//
+
+#include "InitializerNode.hpp"
+
+#include <iostream>                  // for operator<<, ostream, basic_ostream
+#include <list>                      // for list
+#include <string>                    // for operator<<, string
+
+#include "AST/Expr.hpp"              // for Expr
+#include "AST/Init.hpp"              // for Designator, Init, ListInit, Sing...
+#include "Common/SemanticError.hpp"  // for SemanticError
+#include "Common/Utility.hpp"        // for maybeBuild
+#include "ExpressionNode.hpp"        // for ExpressionNode
+#include "DeclarationNode.hpp"       // for buildList
+
+using namespace std;
+
+static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) {
+	return maybeConstructed ? ast::MaybeConstruct : ast::NoConstruct;
+}
+
+InitializerNode::InitializerNode( ExpressionNode * _expr, bool aggrp, ExpressionNode * des )
+		: expr( _expr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ), isDelete( false ) {
+	if ( aggrp )
+		kids = next;
+
+	if ( kids )
+		set_last( nullptr );
+} // InitializerNode::InitializerNode
+
+InitializerNode::InitializerNode( InitializerNode * init, bool aggrp, ExpressionNode * des )
+		: expr( nullptr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ), isDelete( false ) {
+	if ( init )
+		set_last( init );
+
+	if ( aggrp )
+		kids = next;
+
+	if ( kids )
+		next = nullptr;
+} // InitializerNode::InitializerNode
+
+InitializerNode::InitializerNode( bool isDelete ) : expr( nullptr ), aggregate( false ), designator( nullptr ), kids( nullptr ), maybeConstructed( false ), isDelete( isDelete ) {}
+
+InitializerNode::~InitializerNode() {
+	delete expr;
+	delete designator;
+	delete kids;
+} // InitializerNode::~InitializerNode
+
+void InitializerNode::print( std::ostream &os, int indent ) const {
+	os << std::string( indent, ' ' ) << "Initializer expression" << std::endl;
+} // InitializerNode::print
+
+void InitializerNode::printOneLine( std::ostream &os ) const {
+	if ( ! aggregate ) {
+		if ( designator ) {
+			os << "designated by: (";
+			ExpressionNode *curdes = designator;
+			while ( curdes != nullptr) {
+				curdes->printOneLine(os);
+				curdes = curdes->next;
+				if ( curdes ) os << ", ";
+			} // while
+			os << ")";
+		} // if
+		if ( expr ) expr->printOneLine( os );
+	} else {  // It's an aggregate
+		os << "[--";
+		if ( next_init() != nullptr )
+			next_init()->printOneLine( os );
+		if (aggregate) os << "--]";
+	} // if
+
+	InitializerNode *moreInit;
+	if ( ( moreInit = next ) ) {
+		moreInit->printOneLine( os );
+	} // if
+} // InitializerNode::printOneLine
+
+ast::Init * InitializerNode::build() const {
+	assertf( ! isDelete, "Should not build delete stmt InitializerNode" );
+	if ( aggregate ) {
+		// steal designators from children
+		std::vector<ast::ptr<ast::Designation>> designlist;
+		InitializerNode * child = next_init();
+		for ( ; child != nullptr ; child = child->next ) {
+			std::deque<ast::ptr<ast::Expr>> desList;
+			buildList( child->designator, desList );
+			designlist.push_back(
+				new ast::Designation( location, std::move( desList ) ) );
+		} // for
+		std::vector<ast::ptr<ast::Init>> initlist;
+		buildList( next_init(), initlist );
+		return new ast::ListInit( location,
+			std::move( initlist ),
+			std::move( designlist ),
+			toConstructFlag( maybeConstructed )
+		);
+	} else if ( get_expression() ) {
+		assertf( get_expression()->expr, "The expression of initializer must have value" );
+		return new ast::SingleInit( location,
+			maybeBuild( get_expression() ),
+			toConstructFlag( maybeConstructed )
+		);
+	} // if
+	return nullptr;
+} // InitializerNode::build
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/InitializerNode.h
===================================================================
--- src/Parser/InitializerNode.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,50 +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.
-//
-// InitializerNode.h --
-//
-// Author           : Andrew Beach
-// Created On       : Wed Apr  5 11:31:00 2023
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Apr  5 11:48:00 2023
-// Update Count     : 0
-//
-
-#pragma once
-
-#include "ParseNode.h"
-
-struct InitializerNode final : public ParseList<InitializerNode> {
-	InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
-	InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
-	InitializerNode( bool isDelete );
-	~InitializerNode();
-	virtual InitializerNode * clone() const { assert( false ); return nullptr; }
-
-	ExpressionNode * get_expression() const { return expr; }
-
-	InitializerNode * set_designators( ExpressionNode * des ) { designator = des; return this; }
-	ExpressionNode * get_designators() const { return designator; }
-
-	InitializerNode * set_maybeConstructed( bool value ) { maybeConstructed = value; return this; }
-	bool get_maybeConstructed() const { return maybeConstructed; }
-
-	bool get_isDelete() const { return isDelete; }
-
-	InitializerNode * next_init() const { return kids; }
-
-	void print( std::ostream & os, int indent = 0 ) const;
-	void printOneLine( std::ostream & ) const;
-
-	virtual ast::Init * build() const;
-private:
-	ExpressionNode * expr;
-	bool aggregate;
-	ExpressionNode * designator;                        // may be list
-	InitializerNode * kids;
-	bool maybeConstructed;
-	bool isDelete;
-}; // InitializerNode
Index: src/Parser/InitializerNode.hpp
===================================================================
--- src/Parser/InitializerNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/InitializerNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,50 @@
+//
+// 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.
+//
+// InitializerNode.hpp --
+//
+// Author           : Andrew Beach
+// Created On       : Wed Apr  5 11:31:00 2023
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Apr  5 11:48:00 2023
+// Update Count     : 0
+//
+
+#pragma once
+
+#include "ParseNode.hpp"
+
+struct InitializerNode final : public ParseList<InitializerNode> {
+	InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
+	InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
+	InitializerNode( bool isDelete );
+	~InitializerNode();
+	virtual InitializerNode * clone() const { assert( false ); return nullptr; }
+
+	ExpressionNode * get_expression() const { return expr; }
+
+	InitializerNode * set_designators( ExpressionNode * des ) { designator = des; return this; }
+	ExpressionNode * get_designators() const { return designator; }
+
+	InitializerNode * set_maybeConstructed( bool value ) { maybeConstructed = value; return this; }
+	bool get_maybeConstructed() const { return maybeConstructed; }
+
+	bool get_isDelete() const { return isDelete; }
+
+	InitializerNode * next_init() const { return kids; }
+
+	void print( std::ostream & os, int indent = 0 ) const;
+	void printOneLine( std::ostream & ) const;
+
+	virtual ast::Init * build() const;
+private:
+	ExpressionNode * expr;
+	bool aggregate;
+	ExpressionNode * designator;                        // may be list
+	InitializerNode * kids;
+	bool maybeConstructed;
+	bool isDelete;
+}; // InitializerNode
Index: src/Parser/ParseNode.cc
===================================================================
--- src/Parser/ParseNode.cc	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,30 +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.
-//
-// ParseNode.cc --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Sat May 16 13:26:29 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Oct  1 23:10:43 2016
-// Update Count     : 127
-//
-
-#include "ParseNode.h"
-using namespace std;
-
-int ParseNode::indent_by = 4;
-
-std::ostream & operator<<( std::ostream & out, const ParseNode * node ) {
-	node->print( out );
-	return out;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/ParseNode.cpp
===================================================================
--- src/Parser/ParseNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/ParseNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+// ParseNode.cpp --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Sat May 16 13:26:29 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Oct  1 23:10:43 2016
+// Update Count     : 127
+//
+
+#include "ParseNode.hpp"
+using namespace std;
+
+int ParseNode::indent_by = 4;
+
+std::ostream & operator<<( std::ostream & out, const ParseNode * node ) {
+	node->print( out );
+	return out;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(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.
-//
-// ParseNode.h --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Sat May 16 13:28:16 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Dec  9 17:39:34 2023
-// Update Count     : 945
-//
-
-#pragma once
-
-#include <algorithm>               // for move
-#include <cassert>                 // for assert, assertf
-#include <iosfwd>                  // for ostream
-#include <iterator>                // for back_insert_iterator
-#include <list>                    // for list
-#include <memory>                  // for unique_ptr, pointer_traits
-#include <string>                  // for string
-
-#include "AST/Expr.hpp"            // for Expr, NameExpr LogicalFlag
-#include "AST/Fwd.hpp"             // for ptr, Decl, DeclWithType,
-#include "AST/Stmt.hpp"            // for Stmt
-#include "Common/CodeLocation.h"   // for CodeLocation
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/UniqueName.h"     // for UniqueName
-#include "Parser/parserutility.h"  // for maybeBuild, maybeCopy
-
-struct DeclarationNode;
-struct InitializerNode;
-struct ExpressionNode;
-struct StatementNode;
-
-
-//##############################################################################
-
-typedef CodeLocation YYLTYPE;
-#define YYLTYPE_IS_DECLARED 1 /* alert the parser that we have our own definition */
-
-extern YYLTYPE yylloc;
-
-struct ParseNode {
-	ParseNode() {}
-	virtual ~ParseNode() {}
-	virtual ParseNode * clone() const = 0;
-
-	virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
-
-	static int indent_by;
-
-	CodeLocation location = yylloc;
-}; // ParseNode
-
-/// Only ever use in the form `struct NAME final : public ParseList<NAME>`!
-template<typename Next>
-struct ParseList : public ParseNode {
-	ParseList() {}
-	virtual ~ParseList() { delete next; };
-	virtual ParseList<Next> * clone() const = 0;
-
-	Next * get_last() {
-		Next * current = static_cast<Next *>( this );
-		while ( current->next != nullptr ) current = current->next;
-		return current;
-	}
-	Next * set_last( Next * newlast ) {
-		if ( newlast != nullptr ) get_last()->next = newlast;
-		return static_cast<Next *>( this );
-	}
-
-	virtual void printList( std::ostream & os, int indent = 0 ) const {
-		print( os, indent );
-		if ( next ) next->print( os, indent );
-	}
-
-	Next * next = nullptr;
-};
-
-template<typename Node>
-void extend( Node *& list, Node * value ) {
-	if ( list ) {
-		extend( list->next, value );
-	} else {
-		list = value;
-	}
-}
-
-// Must harmonize with OperName.
-enum class OperKinds {
-	// diadic
-	SizeOf, AlignOf, OffsetOf, Plus, Minus, Exp, Mul, Div, Mod, Or, And,
-	BitOr, BitAnd, Xor, Cast, LShift, RShift, LThan, GThan, LEThan, GEThan, Eq, Neq,
-	Assign, AtAssn, ExpAssn, MulAssn, DivAssn, ModAssn, PlusAssn, MinusAssn, LSAssn, RSAssn, AndAssn, ERAssn, OrAssn,
-	Index, Range,
-	// monadic
-	UnPlus, UnMinus, AddressOf, PointTo, Neg, BitNeg, Incr, IncrPost, Decr, DecrPost,
-	Ctor, Dtor,
-}; // OperKinds
-
-enum class EnumHiding { Visible, Hide };
-
-struct LabelNode {
-	std::vector<ast::Label> labels;
-};
-
-std::ostream & operator<<( std::ostream & out, const ParseNode * node );
-
-__attribute__((noreturn)) static inline void SemanticError( const ParseNode * obj, const std::string & error ) {
-	SemanticError( obj->location, toString( error, obj ) );
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/ParseNode.hpp
===================================================================
--- src/Parser/ParseNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/ParseNode.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.
+//
+// ParseNode.hpp --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Sat May 16 13:28:16 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Dec  9 17:39:34 2023
+// Update Count     : 945
+//
+
+#pragma once
+
+#include <algorithm>                 // for move
+#include <cassert>                   // for assert, assertf
+#include <iosfwd>                    // for ostream
+#include <iterator>                  // for back_insert_iterator
+#include <list>                      // for list
+#include <memory>                    // for unique_ptr, pointer_traits
+#include <string>                    // for string
+
+#include "AST/Expr.hpp"              // for Expr, NameExpr, LogicalFlag
+#include "AST/Fwd.hpp"               // for ptr, Decl, DeclWithType,
+#include "AST/Stmt.hpp"              // for Stmt
+#include "Common/CodeLocation.hpp"   // for CodeLocation
+#include "Common/SemanticError.hpp"  // for SemanticError
+#include "Common/UniqueName.hpp"     // for UniqueName
+#include "Parser/ParserUtility.hpp"  // for maybeBuild, maybeCopy
+
+struct DeclarationNode;
+struct InitializerNode;
+struct ExpressionNode;
+struct StatementNode;
+
+
+//##############################################################################
+
+typedef CodeLocation YYLTYPE;
+#define YYLTYPE_IS_DECLARED 1 /* alert the parser that we have our own definition */
+
+extern YYLTYPE yylloc;
+
+struct ParseNode {
+	ParseNode() {}
+	virtual ~ParseNode() {}
+	virtual ParseNode * clone() const = 0;
+
+	virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
+
+	static int indent_by;
+
+	CodeLocation location = yylloc;
+}; // ParseNode
+
+/// Only ever use in the form `struct NAME final : public ParseList<NAME>`!
+template<typename Next>
+struct ParseList : public ParseNode {
+	ParseList() {}
+	virtual ~ParseList() { delete next; };
+	virtual ParseList<Next> * clone() const = 0;
+
+	Next * get_last() {
+		Next * current = static_cast<Next *>( this );
+		while ( current->next != nullptr ) current = current->next;
+		return current;
+	}
+	Next * set_last( Next * newlast ) {
+		if ( newlast != nullptr ) get_last()->next = newlast;
+		return static_cast<Next *>( this );
+	}
+
+	virtual void printList( std::ostream & os, int indent = 0 ) const {
+		print( os, indent );
+		if ( next ) next->print( os, indent );
+	}
+
+	Next * next = nullptr;
+};
+
+template<typename Node>
+void extend( Node *& list, Node * value ) {
+	if ( list ) {
+		extend( list->next, value );
+	} else {
+		list = value;
+	}
+}
+
+// Must harmonize with OperName.
+enum class OperKinds {
+	// diadic
+	SizeOf, AlignOf, OffsetOf, Plus, Minus, Exp, Mul, Div, Mod, Or, And,
+	BitOr, BitAnd, Xor, Cast, LShift, RShift, LThan, GThan, LEThan, GEThan, Eq, Neq,
+	Assign, AtAssn, ExpAssn, MulAssn, DivAssn, ModAssn, PlusAssn, MinusAssn, LSAssn, RSAssn, AndAssn, ERAssn, OrAssn,
+	Index, Range,
+	// monadic
+	UnPlus, UnMinus, AddressOf, PointTo, Neg, BitNeg, Incr, IncrPost, Decr, DecrPost,
+	Ctor, Dtor,
+}; // OperKinds
+
+enum class EnumHiding { Visible, Hide };
+
+struct LabelNode {
+	std::vector<ast::Label> labels;
+};
+
+std::ostream & operator<<( std::ostream & out, const ParseNode * node );
+
+__attribute__((noreturn)) static inline void SemanticError( const ParseNode * obj, const std::string & error ) {
+	SemanticError( obj->location, toString( error, obj ) );
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/ParserTypes.h
===================================================================
--- src/Parser/ParserTypes.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,47 +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.
-//
-// parser.hh --
-//
-// Author           : Peter A. Buhr
-// Created On       : Sat Sep 22 08:58:10 2001
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Feb 15 11:04:40 2020
-// Update Count     : 351
-//
-
-#pragma once
-
-int yylex();
-void yyerror( const char * );
-
-#include <string>
-#include "ParseNode.h"
-// External declarations for information sharing between lexer and scanner
-class TypedefTable;
-extern TypedefTable typedefTable;
-
-// current location in the input
-extern int yylineno;
-extern char * yyfilename;
-
-struct Location {
-    char * file;
-    int line;
-}; // Location
-
-struct Token {
-    std::string * str;									// must be pointer as used in union
-    Location loc;
-
-    operator std::string *() { return str; }
-}; // Token
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/ParserTypes.hpp
===================================================================
--- src/Parser/ParserTypes.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/ParserTypes.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,47 @@
+//
+// 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.
+//
+// ParserTypes.hpp --
+//
+// Author           : Peter A. Buhr
+// Created On       : Sat Sep 22 08:58:10 2001
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Feb 15 11:04:40 2020
+// Update Count     : 351
+//
+
+#pragma once
+
+int yylex();
+void yyerror( const char * );
+
+#include <string>
+#include "ParseNode.hpp"
+// External declarations for information sharing between lexer and scanner
+class TypedefTable;
+extern TypedefTable typedefTable;
+
+// current location in the input
+extern int yylineno;
+extern char * yyfilename;
+
+struct Location {
+    char * file;
+    int line;
+}; // Location
+
+struct Token {
+    std::string * str;									// must be pointer as used in union
+    Location loc;
+
+    operator std::string *() { return str; }
+}; // Token
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/ParserUtility.hpp
===================================================================
--- src/Parser/ParserUtility.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/ParserUtility.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,41 @@
+//
+// 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.
+//
+// ParserUtility.hpp -- Collected utilities for the parser.
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Sat May 16 15:31:46 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Apr  4 14:03:00 2023
+// Update Count     : 7
+//
+
+#pragma once
+
+#include "AST/Copy.hpp"            // for shallowCopy
+
+template< typename T >
+static inline auto maybeBuild( T * orig ) -> decltype(orig->build()) {
+	return (orig) ? orig->build() : nullptr;
+}
+
+template< typename T >
+static inline auto maybeMoveBuild( T * orig ) -> decltype(orig->build()) {
+	auto ret = maybeBuild<T>(orig);
+	delete orig;
+	return ret;
+}
+
+template<typename node_t>
+static inline node_t * maybeCopy( node_t const * node ) {
+	return node ? ast::shallowCopy( node ) : nullptr;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/RunParser.cpp
===================================================================
--- src/Parser/RunParser.cpp	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ src/Parser/RunParser.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -18,6 +18,6 @@
 #include "AST/TranslationUnit.hpp"          // for TranslationUnit
 #include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
-#include "Parser/DeclarationNode.h"         // for DeclarationNode, buildList
-#include "Parser/TypedefTable.h"            // for TypedefTable
+#include "Parser/DeclarationNode.hpp"       // for DeclarationNode, buildList
+#include "Parser/TypedefTable.hpp"          // for TypedefTable
 
 // Variables global to the parsing code.
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,527 +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.
-//
-// StatementNode.cc -- Transform from parse data-structures to AST data-structures, usually deleting the parse
-//     data-structure after the transformation.
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Sat May 16 14:59:41 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Aug 11 11:44:15 2023
-// Update Count     : 429
-//
-
-#include "StatementNode.h"
-
-#include <cassert>                 // for assert, strict_dynamic_cast, assertf
-#include <memory>                  // for unique_ptr
-#include <string>                  // for string
-
-#include "AST/Label.hpp"           // for Label
-#include "AST/Stmt.hpp"            // for Stmt, AsmStmt, BranchStmt, CaseCla...
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild
-#include "DeclarationNode.h"       // for DeclarationNode
-#include "ExpressionNode.h"        // for ExpressionNode
-#include "parserutility.h"         // for notZeroExpr
-
-class Declaration;
-
-using namespace std;
-
-// Some helpers for cases that really want a single node but check for lists.
-static const ast::Stmt * buildMoveSingle( StatementNode * node ) {
-	std::vector<ast::ptr<ast::Stmt>> list;
-	buildMoveList( node, list );
-	assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" );
-	return list.front().release();
-}
-
-static const ast::Stmt * buildMoveOptional( StatementNode * node ) {
-	std::vector<ast::ptr<ast::Stmt>> list;
-	buildMoveList( node, list );
-	assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" );
-	return list.empty() ? nullptr : list.front().release();
-}
-
-StatementNode::StatementNode( DeclarationNode * decl ) {
-	assert( decl );
-	DeclarationNode * agg = decl->extractAggregate();
-	if ( agg ) {
-		StatementNode * nextStmt = new StatementNode(
-			new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
-		next = nextStmt;
-		if ( decl->next ) {
-			next->next = new StatementNode( decl->next );
-			decl->next = nullptr;
-		} // if
-	} else {
-		if ( decl->next ) {
-			next = new StatementNode( decl->next );
-			decl->next = nullptr;
-		} // if
-		agg = decl;
-	} // if
-	// Local copy to avoid accessing the pointer after it is moved from.
-	CodeLocation declLocation = agg->location;
-	stmt.reset( new ast::DeclStmt( declLocation, maybeMoveBuild( agg ) ) );
-} // StatementNode::StatementNode
-
-StatementNode * StatementNode::add_label(
-		const CodeLocation & location,
-		const std::string * name,
-		DeclarationNode * attr ) {
-	stmt->labels.emplace_back( location,
-		*name,
-		attr ? std::move( attr->attributes )
-			: std::vector<ast::ptr<ast::Attribute>>{} );
-	delete attr;
-	delete name;
-	return this;
-}
-
-ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
-	ClauseNode * prev = this;
-	// find end of list and maintain previous pointer
-	for ( ClauseNode * curr = prev; curr != nullptr; curr = curr->next ) {
-		ClauseNode * node = curr;
-		assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
-		prev = curr;
-	} // for
-	ClauseNode * node = prev;
-	// convert from StatementNode list to Statement list
-	std::vector<ast::ptr<ast::Stmt>> stmts;
-	buildMoveList( stmt, stmts );
-	// splice any new Statements to end of current Statements
-	auto caseStmt = strict_dynamic_cast<ast::CaseClause *>( node->clause.get() );
-	for ( auto const & newStmt : stmts ) {
-		caseStmt->stmts.emplace_back( newStmt );
-	}
-	stmts.clear();
-	return this;
-} // ClauseNode::append_last_case
-
-ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
-	if ( ast::Expr * e = maybeMoveBuild( ctl ) ) {
-		return new ast::ExprStmt( location, e );
-	} else {
-		return new ast::NullStmt( location );
-	}
-} // build_expr
-
-static ast::Expr * build_if_control( CondCtl * ctl,
-		std::vector<ast::ptr<ast::Stmt>> & inits ) {
-	assert( inits.empty() );
-	if ( nullptr != ctl->init ) {
-		buildMoveList( ctl->init, inits );
-	} // if
-
-	ast::Expr * cond = nullptr;
-	if ( ctl->condition ) {
-		cond = maybeMoveBuild( ctl->condition );
-	} else {
-		for ( ast::ptr<ast::Stmt> & stmt : inits ) {
-			// build the && of all of the declared variables compared against 0
-			auto declStmt = stmt.strict_as<ast::DeclStmt>();
-			auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
-			ast::Expr * nze = new ast::VariableExpr( dwt->location, dwt );
-			cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
-		}
-	}
-	delete ctl;
-	return cond;
-} // build_if_control
-
-ast::Stmt * build_if( const CodeLocation & location, CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
-	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
-	ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
-
-	ast::Stmt const * astthen = buildMoveSingle( then );
-	ast::Stmt const * astelse = buildMoveOptional( else_ );
-
-	return new ast::IfStmt( location, astcond, astthen, astelse,
-		std::move( astinit )
-	);
-} // build_if
-
-ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
-	std::vector<ast::ptr<ast::CaseClause>> aststmt;
-	buildMoveList( stmt, aststmt );
-	// If it is not a switch it is a choose statement.
-	if ( ! isSwitch ) {
-		for ( ast::ptr<ast::CaseClause> & stmt : aststmt ) {
-			// Code after "case" is the end of case list.
-			if ( !stmt->stmts.empty() ) {
-				auto mutStmt = ast::mutate( stmt.get() );
-				// I believe the stmts are actually always one block.
-				auto stmts = mutStmt->stmts.front().get_and_mutate();
-				auto block = strict_dynamic_cast<ast::CompoundStmt *>( stmts );
-				block->kids.push_back( new ast::BranchStmt( block->location,
-					ast::BranchStmt::Break,
-					ast::Label( block->location ) ) );
-				stmt = mutStmt;
-			} // if
-		} // for
-	} // if
-	// aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
-	return new ast::SwitchStmt( location,
-		maybeMoveBuild( ctl ), std::move( aststmt ) );
-} // build_switch
-
-ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
-	// stmt starts empty and then added to
-	auto expr = maybeMoveBuild( ctl );
-	return new ast::CaseClause( location, expr, {} );
-} // build_case
-
-ast::CaseClause * build_default( const CodeLocation & location ) {
-	// stmt starts empty and then added to
-	return new ast::CaseClause( location, nullptr, {} );
-} // build_default
-
-ast::Stmt * build_while( const CodeLocation & location, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
-	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
-	ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
-
-	return new ast::WhileDoStmt( location,
-		astcond,
-		buildMoveSingle( stmt ),
-		buildMoveOptional( else_ ),
-		std::move( astinit ),
-		ast::While
-	);
-} // build_while
-
-ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
-	// do-while cannot have declarations in the contitional, so init is always empty
-	return new ast::WhileDoStmt( location,
-		maybeMoveBuild( ctl ),
-		buildMoveSingle( stmt ),
-		buildMoveOptional( else_ ),
-		{},
-		ast::DoWhile
-	);
-} // build_do_while
-
-ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
-	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
-	buildMoveList( forctl->init, astinit );
-
-	ast::Expr * astcond = nullptr;						// maybe empty
-	astcond = maybeMoveBuild( forctl->condition );
-
-	ast::Expr * astincr = nullptr;						// maybe empty
-	astincr = maybeMoveBuild( forctl->change );
-	delete forctl;
-
-	return new ast::ForStmt( location,
-		std::move( astinit ),
-		astcond,
-		astincr,
-		buildMoveSingle( stmt ),
-		buildMoveOptional( else_ )
-	);
-} // build_for
-
-ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) {
-	return new ast::BranchStmt( location,
-		kind,
-		ast::Label( location )
-	);
-} // build_branch
-
-ast::Stmt * build_branch( const CodeLocation & location, string * identifier, ast::BranchStmt::Kind kind ) {
-	ast::Stmt * ret = new ast::BranchStmt( location,
-		kind,
-		ast::Label( location, *identifier )
-	);
-	delete identifier; 									// allocated by lexer
-	return ret;
-} // build_branch
-
-ast::Stmt * build_computedgoto( ExpressionNode * ctl ) {
-	ast::Expr * expr = maybeMoveBuild( ctl );
-	return new ast::BranchStmt( expr->location, expr );
-} // build_computedgoto
-
-ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) {
-	std::vector<ast::ptr<ast::Expr>> exps;
-	buildMoveList( ctl, exps );
-	return new ast::ReturnStmt( location,
-		exps.size() > 0 ? exps.back().release() : nullptr
-	);
-} // build_return
-
-static ast::Stmt * build_throw_stmt(
-		const CodeLocation & location,
-		ExpressionNode * ctl,
-		ast::ExceptionKind kind ) {
-	std::vector<ast::ptr<ast::Expr>> exps;
-	buildMoveList( ctl, exps );
-	assertf( exps.size() < 2, "CFA internal error: leaking memory" );
-	return new ast::ThrowStmt( location,
-		kind,
-		!exps.empty() ? exps.back().release() : nullptr,
-		(ast::Expr *)nullptr
-	);
-}
-
-ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) {
-	return build_throw_stmt( loc, ctl, ast::Terminate );
-} // build_throw
-
-ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) {
-	return build_throw_stmt( loc, ctl, ast::Resume );
-} // build_resume
-
-ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
-	(void)ctl;
-	(void)target;
-	assertf( false, "resume at (non-local throw) is not yet supported," );
-} // build_resume_at
-
-ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
-	std::vector<ast::ptr<ast::CatchClause>> aststmt;
-	buildMoveList( catch_, aststmt );
-	ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
-	ast::FinallyClause * finallyBlock = nullptr;
-	if ( finally_ ) {
-		finallyBlock = dynamic_cast<ast::FinallyClause *>( finally_->clause.release() );
-	}
-	return new ast::TryStmt( location,
-		tryBlock,
-		std::move( aststmt ),
-		finallyBlock
-	);
-} // build_try
-
-ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
-	return new ast::CatchClause( location,
-		kind,
-		maybeMoveBuild( decl ),
-		maybeMoveBuild( cond ),
-		buildMoveSingle( body )
-	);
-} // build_catch
-
-ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
-	return new ast::FinallyClause( location,
-		strict_dynamic_cast<const ast::CompoundStmt *>(
-			buildMoveSingle( stmt )
-		)
-	);
-} // build_finally
-
-ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
-	return new ast::SuspendStmt( location,
-		strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
-			buildMoveOptional( then )
-		),
-		kind
-	);
-} // build_suspend
-
-ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
-	auto clause = new ast::WaitForClause( location );
-	clause->target = maybeBuild( targetExpr );
-	clause->stmt = maybeMoveBuild( stmt );
-	clause->when_cond = maybeMoveBuild( when );
-
-	ExpressionNode * next = targetExpr->next;
-	targetExpr->next = nullptr;
-	buildMoveList( next, clause->target_args );
-
-	delete targetExpr;
-
-	existing->clauses.insert( existing->clauses.begin(), clause );
-
-	return existing;
-} // build_waitfor
-
-ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
-	existing->else_stmt = maybeMoveBuild( stmt );
-	existing->else_cond = maybeMoveBuild( when );
-
-	(void)location;
-	return existing;
-} // build_waitfor_else
-
-ast::WaitForStmt * build_waitfor_timeout( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
-	existing->timeout_time = maybeMoveBuild( timeout );
-	existing->timeout_stmt = maybeMoveBuild( stmt );
-	existing->timeout_cond = maybeMoveBuild( when );
-
-	(void)location;
-	return existing;
-} // build_waitfor_timeout
-
-ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
-	ast::WhenClause * clause = new ast::WhenClause( loc );
-	clause->when_cond = maybeMoveBuild( when );
-	clause->stmt = maybeMoveBuild( stmt );
-	clause->target = maybeMoveBuild( targetExpr );
-	return new ast::WaitUntilStmt::ClauseNode( clause );
-}
-ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
-	ast::WhenClause * clause = new ast::WhenClause( loc );
-	clause->when_cond = maybeMoveBuild( when );
-	clause->stmt = maybeMoveBuild( stmt );
-	return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
-}
-
-ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) {
-	ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );
-	retStmt->predicateTree = root;
-
-	// iterative tree traversal
-	std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal
-	ast::WaitUntilStmt::ClauseNode * currNode = nullptr;
-	ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;
-	ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout
-	nodeStack.push_back(root);
-
-	do {
-		currNode = nodeStack.back();
-		nodeStack.pop_back(); // remove node since it will be processed
-
-		switch (currNode->op) {
-		case ast::WaitUntilStmt::ClauseNode::LEAF:
-			retStmt->clauses.push_back(currNode->leaf);
-			break;
-		case ast::WaitUntilStmt::ClauseNode::ELSE:
-			retStmt->else_stmt = currNode->leaf->stmt
-				? ast::deepCopy( currNode->leaf->stmt )
-				: nullptr;
-			retStmt->else_cond = currNode->leaf->when_cond
-				? ast::deepCopy( currNode->leaf->when_cond )
-				: nullptr;
-
-			delete currNode->leaf;
-			break;
-		case ast::WaitUntilStmt::ClauseNode::TIMEOUT:
-			retStmt->timeout_time = currNode->leaf->target
-				? ast::deepCopy( currNode->leaf->target )
-				: nullptr;
-			retStmt->timeout_stmt = currNode->leaf->stmt
-				? ast::deepCopy( currNode->leaf->stmt )
-				: nullptr;
-			retStmt->timeout_cond = currNode->leaf->when_cond
-				? ast::deepCopy( currNode->leaf->when_cond )
-				: nullptr;
-
-			delete currNode->leaf;
-			break;
-		default:
-			nodeStack.push_back( currNode->right ); // process right after left
-			nodeStack.push_back( currNode->left );
-
-			// Cut else/timeout out of the tree
-			if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {
-				if ( lastInternalNode )
-					lastInternalNode->right = currNode->left;
-				else // if not set then root is LEFT_OR
-					retStmt->predicateTree = currNode->left;
-
-				currNode->left = nullptr;
-				cleanup = currNode;
-			}
-
-			lastInternalNode = currNode;
-			break;
-		}
-	} while ( !nodeStack.empty() );
-
-	if ( cleanup ) delete cleanup;
-
-	return retStmt;
-}
-
-ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
-	std::vector<ast::ptr<ast::Expr>> e;
-	buildMoveList( exprs, e );
-	ast::Stmt * s = maybeMoveBuild( stmt );
-	return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) );
-} // build_with
-
-ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) {
-	auto cs = new ast::CompoundStmt( location );
-	buildMoveList( first, cs->kids );
-	return cs;
-} // build_compound
-
-// A single statement in a control structure is always converted to a compound statement so subsequent generated code
-// can be placed within this compound statement. Otherwise, code generation has to constantly check for a single
-// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
-// conical form for code generation.
-StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) {
-	// Optimization: if the control-structure statement is a compound statement, do not wrap it.
-	// e.g., if (...) {...} do not wrap the existing compound statement.
-	if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
-		return new StatementNode( build_compound( location, first ) );
-	} // if
-	return first;
-} // maybe_build_compound
-
-// Question
-ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
-	std::vector<ast::ptr<ast::Expr>> out, in;
-	std::vector<ast::ptr<ast::ConstantExpr>> clob;
-
-	buildMoveList( output, out );
-	buildMoveList( input, in );
-	buildMoveList( clobber, clob );
-	return new ast::AsmStmt( location,
-		is_volatile,
-		maybeMoveBuild( instruction ),
-		std::move( out ),
-		std::move( in ),
-		std::move( clob ),
-		gotolabels ? gotolabels->labels : std::vector<ast::Label>()
-	);
-} // build_asm
-
-ast::Stmt * build_directive( const CodeLocation & location, string * directive ) {
-	auto stmt = new ast::DirectiveStmt( location, *directive );
-	delete directive;
-	return stmt;
-} // build_directive
-
-ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
-	std::vector<ast::ptr<ast::Expr>> expList;
-	buildMoveList( exprs, expList );
-	ast::Stmt * body = maybeMoveBuild( stmt );
-	return new ast::MutexStmt( location, body, std::move( expList ) );
-} // build_mutex
-
-ast::Stmt * build_corun( const CodeLocation & location, StatementNode * stmt ) {
-	ast::Stmt * body = maybeMoveBuild( stmt );
-	return new ast::CorunStmt( location, body );
-} // build_corun
-
-ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ) {
-	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
-	buildMoveList( forctl->init, astinit );
-
-	ast::Expr * astcond = nullptr;						// maybe empty
-	astcond = maybeMoveBuild( forctl->condition );
-
-	ast::Expr * astincr = nullptr;						// maybe empty
-	astincr = maybeMoveBuild( forctl->change );
-	delete forctl;
-
-	return new ast::CoforStmt( location,
-		std::move( astinit ),
-		astcond,
-		astincr,
-		buildMoveSingle( stmt )
-	);
-} // build_cofor
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/StatementNode.cpp
===================================================================
--- src/Parser/StatementNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/StatementNode.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,527 @@
+//
+// 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.
+//
+// StatementNode.cpp -- Transform from parse data-structures to AST data-structures, usually deleting the parse
+//     data-structure after the transformation.
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Sat May 16 14:59:41 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri Aug 11 11:44:15 2023
+// Update Count     : 429
+//
+
+#include "StatementNode.hpp"
+
+#include <cassert>                 // for assert, strict_dynamic_cast, assertf
+#include <memory>                  // for unique_ptr
+#include <string>                  // for string
+
+#include "AST/Label.hpp"           // for Label
+#include "AST/Stmt.hpp"            // for Stmt, AsmStmt, BranchStmt, CaseCla...
+#include "Common/SemanticError.hpp"// for SemanticError
+#include "Common/Utility.hpp"      // for maybeMoveBuild, maybeBuild
+#include "DeclarationNode.hpp"     // for DeclarationNode
+#include "ExpressionNode.hpp"      // for ExpressionNode
+#include "ParserUtility.hpp"       // for notZeroExpr
+
+class Declaration;
+
+using namespace std;
+
+// Some helpers for cases that really want a single node but check for lists.
+static const ast::Stmt * buildMoveSingle( StatementNode * node ) {
+	std::vector<ast::ptr<ast::Stmt>> list;
+	buildMoveList( node, list );
+	assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" );
+	return list.front().release();
+}
+
+static const ast::Stmt * buildMoveOptional( StatementNode * node ) {
+	std::vector<ast::ptr<ast::Stmt>> list;
+	buildMoveList( node, list );
+	assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" );
+	return list.empty() ? nullptr : list.front().release();
+}
+
+StatementNode::StatementNode( DeclarationNode * decl ) {
+	assert( decl );
+	DeclarationNode * agg = decl->extractAggregate();
+	if ( agg ) {
+		StatementNode * nextStmt = new StatementNode(
+			new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
+		next = nextStmt;
+		if ( decl->next ) {
+			next->next = new StatementNode( decl->next );
+			decl->next = nullptr;
+		} // if
+	} else {
+		if ( decl->next ) {
+			next = new StatementNode( decl->next );
+			decl->next = nullptr;
+		} // if
+		agg = decl;
+	} // if
+	// Local copy to avoid accessing the pointer after it is moved from.
+	CodeLocation declLocation = agg->location;
+	stmt.reset( new ast::DeclStmt( declLocation, maybeMoveBuild( agg ) ) );
+} // StatementNode::StatementNode
+
+StatementNode * StatementNode::add_label(
+		const CodeLocation & location,
+		const std::string * name,
+		DeclarationNode * attr ) {
+	stmt->labels.emplace_back( location,
+		*name,
+		attr ? std::move( attr->attributes )
+			: std::vector<ast::ptr<ast::Attribute>>{} );
+	delete attr;
+	delete name;
+	return this;
+}
+
+ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
+	ClauseNode * prev = this;
+	// find end of list and maintain previous pointer
+	for ( ClauseNode * curr = prev; curr != nullptr; curr = curr->next ) {
+		ClauseNode * node = curr;
+		assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
+		prev = curr;
+	} // for
+	ClauseNode * node = prev;
+	// convert from StatementNode list to Statement list
+	std::vector<ast::ptr<ast::Stmt>> stmts;
+	buildMoveList( stmt, stmts );
+	// splice any new Statements to end of current Statements
+	auto caseStmt = strict_dynamic_cast<ast::CaseClause *>( node->clause.get() );
+	for ( auto const & newStmt : stmts ) {
+		caseStmt->stmts.emplace_back( newStmt );
+	}
+	stmts.clear();
+	return this;
+} // ClauseNode::append_last_case
+
+ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
+	if ( ast::Expr * e = maybeMoveBuild( ctl ) ) {
+		return new ast::ExprStmt( location, e );
+	} else {
+		return new ast::NullStmt( location );
+	}
+} // build_expr
+
+static ast::Expr * build_if_control( CondCtl * ctl,
+		std::vector<ast::ptr<ast::Stmt>> & inits ) {
+	assert( inits.empty() );
+	if ( nullptr != ctl->init ) {
+		buildMoveList( ctl->init, inits );
+	} // if
+
+	ast::Expr * cond = nullptr;
+	if ( ctl->condition ) {
+		cond = maybeMoveBuild( ctl->condition );
+	} else {
+		for ( ast::ptr<ast::Stmt> & stmt : inits ) {
+			// build the && of all of the declared variables compared against 0
+			auto declStmt = stmt.strict_as<ast::DeclStmt>();
+			auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
+			ast::Expr * nze = new ast::VariableExpr( dwt->location, dwt );
+			cond = cond ? new ast::LogicalExpr( dwt->location, cond, nze, ast::AndExpr ) : nze;
+		}
+	}
+	delete ctl;
+	return cond;
+} // build_if_control
+
+ast::Stmt * build_if( const CodeLocation & location, CondCtl * ctl, StatementNode * then, StatementNode * else_ ) {
+	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
+	ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
+
+	ast::Stmt const * astthen = buildMoveSingle( then );
+	ast::Stmt const * astelse = buildMoveOptional( else_ );
+
+	return new ast::IfStmt( location, astcond, astthen, astelse,
+		std::move( astinit )
+	);
+} // build_if
+
+ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
+	std::vector<ast::ptr<ast::CaseClause>> aststmt;
+	buildMoveList( stmt, aststmt );
+	// If it is not a switch it is a choose statement.
+	if ( ! isSwitch ) {
+		for ( ast::ptr<ast::CaseClause> & stmt : aststmt ) {
+			// Code after "case" is the end of case list.
+			if ( !stmt->stmts.empty() ) {
+				auto mutStmt = ast::mutate( stmt.get() );
+				// I believe the stmts are actually always one block.
+				auto stmts = mutStmt->stmts.front().get_and_mutate();
+				auto block = strict_dynamic_cast<ast::CompoundStmt *>( stmts );
+				block->kids.push_back( new ast::BranchStmt( block->location,
+					ast::BranchStmt::Break,
+					ast::Label( block->location ) ) );
+				stmt = mutStmt;
+			} // if
+		} // for
+	} // if
+	// aststmt.size() == 0 for switch (...) {}, i.e., no declaration or statements
+	return new ast::SwitchStmt( location,
+		maybeMoveBuild( ctl ), std::move( aststmt ) );
+} // build_switch
+
+ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
+	// stmt starts empty and then added to
+	auto expr = maybeMoveBuild( ctl );
+	return new ast::CaseClause( location, expr, {} );
+} // build_case
+
+ast::CaseClause * build_default( const CodeLocation & location ) {
+	// stmt starts empty and then added to
+	return new ast::CaseClause( location, nullptr, {} );
+} // build_default
+
+ast::Stmt * build_while( const CodeLocation & location, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ ) {
+	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
+	ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
+
+	return new ast::WhileDoStmt( location,
+		astcond,
+		buildMoveSingle( stmt ),
+		buildMoveOptional( else_ ),
+		std::move( astinit ),
+		ast::While
+	);
+} // build_while
+
+ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
+	// do-while cannot have declarations in the contitional, so init is always empty
+	return new ast::WhileDoStmt( location,
+		maybeMoveBuild( ctl ),
+		buildMoveSingle( stmt ),
+		buildMoveOptional( else_ ),
+		{},
+		ast::DoWhile
+	);
+} // build_do_while
+
+ast::Stmt * build_for( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ ) {
+	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
+	buildMoveList( forctl->init, astinit );
+
+	ast::Expr * astcond = nullptr;						// maybe empty
+	astcond = maybeMoveBuild( forctl->condition );
+
+	ast::Expr * astincr = nullptr;						// maybe empty
+	astincr = maybeMoveBuild( forctl->change );
+	delete forctl;
+
+	return new ast::ForStmt( location,
+		std::move( astinit ),
+		astcond,
+		astincr,
+		buildMoveSingle( stmt ),
+		buildMoveOptional( else_ )
+	);
+} // build_for
+
+ast::Stmt * build_branch( const CodeLocation & location, ast::BranchStmt::Kind kind ) {
+	return new ast::BranchStmt( location,
+		kind,
+		ast::Label( location )
+	);
+} // build_branch
+
+ast::Stmt * build_branch( const CodeLocation & location, string * identifier, ast::BranchStmt::Kind kind ) {
+	ast::Stmt * ret = new ast::BranchStmt( location,
+		kind,
+		ast::Label( location, *identifier )
+	);
+	delete identifier; 									// allocated by lexer
+	return ret;
+} // build_branch
+
+ast::Stmt * build_computedgoto( ExpressionNode * ctl ) {
+	ast::Expr * expr = maybeMoveBuild( ctl );
+	return new ast::BranchStmt( expr->location, expr );
+} // build_computedgoto
+
+ast::Stmt * build_return( const CodeLocation & location, ExpressionNode * ctl ) {
+	std::vector<ast::ptr<ast::Expr>> exps;
+	buildMoveList( ctl, exps );
+	return new ast::ReturnStmt( location,
+		exps.size() > 0 ? exps.back().release() : nullptr
+	);
+} // build_return
+
+static ast::Stmt * build_throw_stmt(
+		const CodeLocation & location,
+		ExpressionNode * ctl,
+		ast::ExceptionKind kind ) {
+	std::vector<ast::ptr<ast::Expr>> exps;
+	buildMoveList( ctl, exps );
+	assertf( exps.size() < 2, "CFA internal error: leaking memory" );
+	return new ast::ThrowStmt( location,
+		kind,
+		!exps.empty() ? exps.back().release() : nullptr,
+		(ast::Expr *)nullptr
+	);
+}
+
+ast::Stmt * build_throw( const CodeLocation & loc, ExpressionNode * ctl ) {
+	return build_throw_stmt( loc, ctl, ast::Terminate );
+} // build_throw
+
+ast::Stmt * build_resume( const CodeLocation & loc, ExpressionNode * ctl ) {
+	return build_throw_stmt( loc, ctl, ast::Resume );
+} // build_resume
+
+ast::Stmt * build_resume_at( ExpressionNode * ctl, ExpressionNode * target ) {
+	(void)ctl;
+	(void)target;
+	assertf( false, "resume at (non-local throw) is not yet supported," );
+} // build_resume_at
+
+ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
+	std::vector<ast::ptr<ast::CatchClause>> aststmt;
+	buildMoveList( catch_, aststmt );
+	ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
+	ast::FinallyClause * finallyBlock = nullptr;
+	if ( finally_ ) {
+		finallyBlock = dynamic_cast<ast::FinallyClause *>( finally_->clause.release() );
+	}
+	return new ast::TryStmt( location,
+		tryBlock,
+		std::move( aststmt ),
+		finallyBlock
+	);
+} // build_try
+
+ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
+	return new ast::CatchClause( location,
+		kind,
+		maybeMoveBuild( decl ),
+		maybeMoveBuild( cond ),
+		buildMoveSingle( body )
+	);
+} // build_catch
+
+ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
+	return new ast::FinallyClause( location,
+		strict_dynamic_cast<const ast::CompoundStmt *>(
+			buildMoveSingle( stmt )
+		)
+	);
+} // build_finally
+
+ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
+	return new ast::SuspendStmt( location,
+		strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
+			buildMoveOptional( then )
+		),
+		kind
+	);
+} // build_suspend
+
+ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
+	auto clause = new ast::WaitForClause( location );
+	clause->target = maybeBuild( targetExpr );
+	clause->stmt = maybeMoveBuild( stmt );
+	clause->when_cond = maybeMoveBuild( when );
+
+	ExpressionNode * next = targetExpr->next;
+	targetExpr->next = nullptr;
+	buildMoveList( next, clause->target_args );
+
+	delete targetExpr;
+
+	existing->clauses.insert( existing->clauses.begin(), clause );
+
+	return existing;
+} // build_waitfor
+
+ast::WaitForStmt * build_waitfor_else( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ) {
+	existing->else_stmt = maybeMoveBuild( stmt );
+	existing->else_cond = maybeMoveBuild( when );
+
+	(void)location;
+	return existing;
+} // build_waitfor_else
+
+ast::WaitForStmt * build_waitfor_timeout( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
+	existing->timeout_time = maybeMoveBuild( timeout );
+	existing->timeout_stmt = maybeMoveBuild( stmt );
+	existing->timeout_cond = maybeMoveBuild( when );
+
+	(void)location;
+	return existing;
+} // build_waitfor_timeout
+
+ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
+	ast::WhenClause * clause = new ast::WhenClause( loc );
+	clause->when_cond = maybeMoveBuild( when );
+	clause->stmt = maybeMoveBuild( stmt );
+	clause->target = maybeMoveBuild( targetExpr );
+	return new ast::WaitUntilStmt::ClauseNode( clause );
+}
+ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
+	ast::WhenClause * clause = new ast::WhenClause( loc );
+	clause->when_cond = maybeMoveBuild( when );
+	clause->stmt = maybeMoveBuild( stmt );
+	return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
+}
+
+ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) {
+	ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );
+	retStmt->predicateTree = root;
+
+	// iterative tree traversal
+	std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal
+	ast::WaitUntilStmt::ClauseNode * currNode = nullptr;
+	ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;
+	ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout
+	nodeStack.push_back(root);
+
+	do {
+		currNode = nodeStack.back();
+		nodeStack.pop_back(); // remove node since it will be processed
+
+		switch (currNode->op) {
+		case ast::WaitUntilStmt::ClauseNode::LEAF:
+			retStmt->clauses.push_back(currNode->leaf);
+			break;
+		case ast::WaitUntilStmt::ClauseNode::ELSE:
+			retStmt->else_stmt = currNode->leaf->stmt
+				? ast::deepCopy( currNode->leaf->stmt )
+				: nullptr;
+			retStmt->else_cond = currNode->leaf->when_cond
+				? ast::deepCopy( currNode->leaf->when_cond )
+				: nullptr;
+
+			delete currNode->leaf;
+			break;
+		case ast::WaitUntilStmt::ClauseNode::TIMEOUT:
+			retStmt->timeout_time = currNode->leaf->target
+				? ast::deepCopy( currNode->leaf->target )
+				: nullptr;
+			retStmt->timeout_stmt = currNode->leaf->stmt
+				? ast::deepCopy( currNode->leaf->stmt )
+				: nullptr;
+			retStmt->timeout_cond = currNode->leaf->when_cond
+				? ast::deepCopy( currNode->leaf->when_cond )
+				: nullptr;
+
+			delete currNode->leaf;
+			break;
+		default:
+			nodeStack.push_back( currNode->right ); // process right after left
+			nodeStack.push_back( currNode->left );
+
+			// Cut else/timeout out of the tree
+			if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {
+				if ( lastInternalNode )
+					lastInternalNode->right = currNode->left;
+				else // if not set then root is LEFT_OR
+					retStmt->predicateTree = currNode->left;
+
+				currNode->left = nullptr;
+				cleanup = currNode;
+			}
+
+			lastInternalNode = currNode;
+			break;
+		}
+	} while ( !nodeStack.empty() );
+
+	if ( cleanup ) delete cleanup;
+
+	return retStmt;
+}
+
+ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
+	std::vector<ast::ptr<ast::Expr>> e;
+	buildMoveList( exprs, e );
+	ast::Stmt * s = maybeMoveBuild( stmt );
+	return new ast::DeclStmt( location, new ast::WithStmt( location, std::move( e ), s ) );
+} // build_with
+
+ast::Stmt * build_compound( const CodeLocation & location, StatementNode * first ) {
+	auto cs = new ast::CompoundStmt( location );
+	buildMoveList( first, cs->kids );
+	return cs;
+} // build_compound
+
+// A single statement in a control structure is always converted to a compound statement so subsequent generated code
+// can be placed within this compound statement. Otherwise, code generation has to constantly check for a single
+// statement and wrap it into a compound statement to insert additional code. Hence, all control structures have a
+// conical form for code generation.
+StatementNode * maybe_build_compound( const CodeLocation & location, StatementNode * first ) {
+	// Optimization: if the control-structure statement is a compound statement, do not wrap it.
+	// e.g., if (...) {...} do not wrap the existing compound statement.
+	if ( !dynamic_cast<ast::CompoundStmt *>( first->stmt.get() ) ) { // unique_ptr
+		return new StatementNode( build_compound( location, first ) );
+	} // if
+	return first;
+} // maybe_build_compound
+
+// Question
+ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
+	std::vector<ast::ptr<ast::Expr>> out, in;
+	std::vector<ast::ptr<ast::ConstantExpr>> clob;
+
+	buildMoveList( output, out );
+	buildMoveList( input, in );
+	buildMoveList( clobber, clob );
+	return new ast::AsmStmt( location,
+		is_volatile,
+		maybeMoveBuild( instruction ),
+		std::move( out ),
+		std::move( in ),
+		std::move( clob ),
+		gotolabels ? gotolabels->labels : std::vector<ast::Label>()
+	);
+} // build_asm
+
+ast::Stmt * build_directive( const CodeLocation & location, string * directive ) {
+	auto stmt = new ast::DirectiveStmt( location, *directive );
+	delete directive;
+	return stmt;
+} // build_directive
+
+ast::Stmt * build_mutex( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
+	std::vector<ast::ptr<ast::Expr>> expList;
+	buildMoveList( exprs, expList );
+	ast::Stmt * body = maybeMoveBuild( stmt );
+	return new ast::MutexStmt( location, body, std::move( expList ) );
+} // build_mutex
+
+ast::Stmt * build_corun( const CodeLocation & location, StatementNode * stmt ) {
+	ast::Stmt * body = maybeMoveBuild( stmt );
+	return new ast::CorunStmt( location, body );
+} // build_corun
+
+ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ) {
+	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
+	buildMoveList( forctl->init, astinit );
+
+	ast::Expr * astcond = nullptr;						// maybe empty
+	astcond = maybeMoveBuild( forctl->condition );
+
+	ast::Expr * astincr = nullptr;						// maybe empty
+	astincr = maybeMoveBuild( forctl->change );
+	delete forctl;
+
+	return new ast::CoforStmt( location,
+		std::move( astinit ),
+		astcond,
+		astincr,
+		buildMoveSingle( stmt )
+	);
+} // build_cofor
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/StatementNode.h
===================================================================
--- src/Parser/StatementNode.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,103 +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.
-//
-// StatementNode.h --
-//
-// Author           : Andrew Beach
-// Created On       : Wed Apr  5 11:42:00 2023
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Aug 11 11:44:07 2023
-// Update Count     : 2
-//
-
-#pragma once
-
-#include "ParseNode.h"
-
-struct StatementNode final : public ParseList<StatementNode> {
-	StatementNode() : stmt( nullptr ) {}
-	StatementNode( ast::Stmt * stmt ) : stmt( stmt ) {}
-	StatementNode( DeclarationNode * decl );
-	virtual ~StatementNode() {}
-
-	virtual StatementNode * clone() const final { assert( false ); return nullptr; }
-	ast::Stmt * build() { return stmt.release(); }
-
-	StatementNode * add_label(
-			const CodeLocation & location,
-			const std::string * name,
-			DeclarationNode * attr = nullptr );
-
-	virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
-		os << stmt.get() << std::endl;
-	}
-
-	std::unique_ptr<ast::Stmt> stmt;
-}; // StatementNode
-
-struct ClauseNode final : public ParseList<ClauseNode> {
-	ClauseNode( ast::StmtClause * clause ) : clause( clause ) {}
-	virtual ~ClauseNode() {}
-
-	virtual ClauseNode * clone() const final { assert( false ); return nullptr; }
-	ast::StmtClause * build() { return clause.release(); }
-
-	virtual ClauseNode * append_last_case( StatementNode * );
-
-	std::unique_ptr<ast::StmtClause> clause;
-};
-
-ast::Stmt * build_expr( CodeLocation const &, ExpressionNode * ctl );
-
-struct CondCtl {
-	CondCtl( DeclarationNode * decl, ExpressionNode * condition ) :
-		init( decl ? new StatementNode( decl ) : nullptr ), condition( condition ) {}
-
-	StatementNode * init;
-	ExpressionNode * condition;
-};
-
-struct ForCtrl {
-	ForCtrl( StatementNode * stmt, ExpressionNode * condition, ExpressionNode * change ) :
-		init( stmt ), condition( condition ), change( change ) {}
-
-	StatementNode * init;
-	ExpressionNode * condition;
-	ExpressionNode * change;
-};
-
-ast::Stmt * build_if( const CodeLocation &, CondCtl * ctl, StatementNode * then, StatementNode * else_ );
-ast::Stmt * build_switch( const CodeLocation &, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt );
-ast::CaseClause * build_case( const CodeLocation &, ExpressionNode * ctl );
-ast::CaseClause * build_default( const CodeLocation & );
-ast::Stmt * build_while( const CodeLocation &, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
-ast::Stmt * build_do_while( const CodeLocation &, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
-ast::Stmt * build_for( const CodeLocation &, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );
-ast::Stmt * build_branch( const CodeLocation &, ast::BranchStmt::Kind kind );
-ast::Stmt * build_branch( const CodeLocation &, std::string * identifier, ast::BranchStmt::Kind kind );
-ast::Stmt * build_computedgoto( ExpressionNode * ctl );
-ast::Stmt * build_return( const CodeLocation &, ExpressionNode * ctl );
-ast::Stmt * build_throw( const CodeLocation &, ExpressionNode * ctl );
-ast::Stmt * build_resume( const CodeLocation &, ExpressionNode * ctl );
-ast::Stmt * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
-ast::Stmt * build_try( const CodeLocation &, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ );
-ast::CatchClause * build_catch( const CodeLocation &, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );
-ast::FinallyClause * build_finally( const CodeLocation &, StatementNode * stmt );
-ast::Stmt * build_compound( const CodeLocation &, StatementNode * first );
-StatementNode * maybe_build_compound( const CodeLocation &, StatementNode * first );
-ast::Stmt * build_asm( const CodeLocation &, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
-ast::Stmt * build_directive( const CodeLocation &, std::string * directive );
-ast::SuspendStmt * build_suspend( const CodeLocation &, StatementNode *, ast::SuspendStmt::Kind );
-ast::WaitForStmt * build_waitfor( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
-ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt );
-ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
-ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
-ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );
-ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );
-ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
-ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
-ast::Stmt * build_corun( const CodeLocation &, StatementNode * stmt );
-ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt );
Index: src/Parser/StatementNode.hpp
===================================================================
--- src/Parser/StatementNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/StatementNode.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,103 @@
+//
+// 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.
+//
+// StatementNode.hpp --
+//
+// Author           : Andrew Beach
+// Created On       : Wed Apr  5 11:42:00 2023
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri Aug 11 11:44:07 2023
+// Update Count     : 2
+//
+
+#pragma once
+
+#include "ParseNode.hpp"
+
+struct StatementNode final : public ParseList<StatementNode> {
+	StatementNode() : stmt( nullptr ) {}
+	StatementNode( ast::Stmt * stmt ) : stmt( stmt ) {}
+	StatementNode( DeclarationNode * decl );
+	virtual ~StatementNode() {}
+
+	virtual StatementNode * clone() const final { assert( false ); return nullptr; }
+	ast::Stmt * build() { return stmt.release(); }
+
+	StatementNode * add_label(
+			const CodeLocation & location,
+			const std::string * name,
+			DeclarationNode * attr = nullptr );
+
+	virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
+		os << stmt.get() << std::endl;
+	}
+
+	std::unique_ptr<ast::Stmt> stmt;
+}; // StatementNode
+
+struct ClauseNode final : public ParseList<ClauseNode> {
+	ClauseNode( ast::StmtClause * clause ) : clause( clause ) {}
+	virtual ~ClauseNode() {}
+
+	virtual ClauseNode * clone() const final { assert( false ); return nullptr; }
+	ast::StmtClause * build() { return clause.release(); }
+
+	virtual ClauseNode * append_last_case( StatementNode * );
+
+	std::unique_ptr<ast::StmtClause> clause;
+};
+
+ast::Stmt * build_expr( CodeLocation const &, ExpressionNode * ctl );
+
+struct CondCtl {
+	CondCtl( DeclarationNode * decl, ExpressionNode * condition ) :
+		init( decl ? new StatementNode( decl ) : nullptr ), condition( condition ) {}
+
+	StatementNode * init;
+	ExpressionNode * condition;
+};
+
+struct ForCtrl {
+	ForCtrl( StatementNode * stmt, ExpressionNode * condition, ExpressionNode * change ) :
+		init( stmt ), condition( condition ), change( change ) {}
+
+	StatementNode * init;
+	ExpressionNode * condition;
+	ExpressionNode * change;
+};
+
+ast::Stmt * build_if( const CodeLocation &, CondCtl * ctl, StatementNode * then, StatementNode * else_ );
+ast::Stmt * build_switch( const CodeLocation &, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt );
+ast::CaseClause * build_case( const CodeLocation &, ExpressionNode * ctl );
+ast::CaseClause * build_default( const CodeLocation & );
+ast::Stmt * build_while( const CodeLocation &, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
+ast::Stmt * build_do_while( const CodeLocation &, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
+ast::Stmt * build_for( const CodeLocation &, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );
+ast::Stmt * build_branch( const CodeLocation &, ast::BranchStmt::Kind kind );
+ast::Stmt * build_branch( const CodeLocation &, std::string * identifier, ast::BranchStmt::Kind kind );
+ast::Stmt * build_computedgoto( ExpressionNode * ctl );
+ast::Stmt * build_return( const CodeLocation &, ExpressionNode * ctl );
+ast::Stmt * build_throw( const CodeLocation &, ExpressionNode * ctl );
+ast::Stmt * build_resume( const CodeLocation &, ExpressionNode * ctl );
+ast::Stmt * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
+ast::Stmt * build_try( const CodeLocation &, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ );
+ast::CatchClause * build_catch( const CodeLocation &, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );
+ast::FinallyClause * build_finally( const CodeLocation &, StatementNode * stmt );
+ast::Stmt * build_compound( const CodeLocation &, StatementNode * first );
+StatementNode * maybe_build_compound( const CodeLocation &, StatementNode * first );
+ast::Stmt * build_asm( const CodeLocation &, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
+ast::Stmt * build_directive( const CodeLocation &, std::string * directive );
+ast::SuspendStmt * build_suspend( const CodeLocation &, StatementNode *, ast::SuspendStmt::Kind );
+ast::WaitForStmt * build_waitfor( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
+ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt );
+ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
+ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
+ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );
+ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );
+ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
+ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
+ast::Stmt * build_corun( const CodeLocation &, StatementNode * stmt );
+ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt );
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,1733 +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.
-//
-// TypeData.cc --
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Sat May 16 15:12:51 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Feb 23 08:58:30 2024
-// Update Count     : 734
-//
-
-#include "TypeData.h"
-
-#include <cassert>                 // for assert
-#include <ostream>                 // for operator<<, ostream, basic_ostream
-
-#include "AST/Attribute.hpp"       // for Attribute
-#include "AST/Decl.hpp"            // for AggregateDecl, ObjectDecl, TypeDe...
-#include "AST/Init.hpp"            // for SingleInit, ListInit
-#include "AST/Print.hpp"           // for print
-#include "AST/Type.hpp"            // for Type
-#include "Common/SemanticError.h"  // for SemanticError
-#include "Common/utility.h"        // for splice, spliceBegin
-#include "Common/Iterate.hpp"      // for reverseIterate
-#include "Parser/ExpressionNode.h" // for ExpressionNode
-#include "Parser/StatementNode.h"  // for StatementNode
-
-class Attribute;
-
-using namespace std;
-
-// These must harmonize with the corresponding enumerations in the header.
-const char * TypeData::basicTypeNames[] = {
-	"void", "_Bool", "char", "int", "int128",
-	"float", "double", "long double", "float80", "float128",
-	"_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x",
-	"NoBasicTypeNames"
-};
-const char * TypeData::complexTypeNames[] = {
-	"_Complex", "NoComplexTypeNames", "_Imaginary"
-}; // Imaginary unsupported => parse, but make invisible and print error message
-const char * TypeData::signednessNames[] = {
-	"signed", "unsigned", "NoSignednessNames"
-};
-const char * TypeData::lengthNames[] = {
-	"short", "long", "long long", "NoLengthNames"
-};
-const char * TypeData::builtinTypeNames[] = {
-	"__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames"
-};
-
-TypeData::TypeData( Kind k ) : location( yylloc ), kind( k ), base( nullptr ), forall( nullptr ) /*, PTR1( (void*)(0xdeadbeefdeadbeef)), PTR2( (void*)(0xdeadbeefdeadbeef) ) */ {
-	switch ( kind ) {
-	case Unknown:
-	case Pointer:
-	case Reference:
-	case EnumConstant:
-	case GlobalScope:
-	case Basic:
-		// No unique data to initialize.
-		break;
-	case Array:
-		array.dimension = nullptr;
-		array.isVarLen = false;
-		array.isStatic = false;
-		break;
-	case Function:
-		function.params = nullptr;
-		function.idList = nullptr;
-		function.oldDeclList = nullptr;
-		function.body = nullptr;
-		function.withExprs = nullptr;
-		break;
-	case Aggregate:
-		aggregate.kind = ast::AggregateDecl::NoAggregate;
-		aggregate.name = nullptr;
-		aggregate.params = nullptr;
-		aggregate.actuals = nullptr;
-		aggregate.fields = nullptr;
-		aggregate.body = false;
-		aggregate.anon = false;
-		aggregate.typed = false;
-		aggregate.hiding = EnumHiding::Visible;
-		break;
-	case AggregateInst:
-		aggInst.aggregate = nullptr;
-		aggInst.params = nullptr;
-		aggInst.hoistType = false;
-		break;
-	case Symbolic:
-	case SymbolicInst:
-		symbolic.name = nullptr;
-		symbolic.params = nullptr;
-		symbolic.actuals = nullptr;
-		symbolic.assertions = nullptr;
-		break;
-	case Tuple:
-		tuple = nullptr;
-		break;
-	case Typeof:
-	case Basetypeof:
-		typeexpr = nullptr;
-		break;
-	case Vtable:
-	case Builtin:
-		// No unique data to initialize.
-		break;
-	case Qualified:
-		qualified.parent = nullptr;
-		qualified.child = nullptr;
-		break;
-	} // switch
-} // TypeData::TypeData
-
-
-TypeData::~TypeData() {
-	delete base;
-	delete forall;
-
-	switch ( kind ) {
-	case Unknown:
-	case Pointer:
-	case Reference:
-	case EnumConstant:
-	case GlobalScope:
-	case Basic:
-		// No unique data to deconstruct.
-		break;
-	case Array:
-		delete array.dimension;
-		break;
-	case Function:
-		delete function.params;
-		delete function.idList;
-		delete function.oldDeclList;
-		delete function.body;
-		delete function.withExprs;
-		break;
-	case Aggregate:
-		delete aggregate.name;
-		delete aggregate.params;
-		delete aggregate.actuals;
-		delete aggregate.fields;
-		break;
-	case AggregateInst:
-		delete aggInst.aggregate;
-		delete aggInst.params;
-		break;
-	case Symbolic:
-	case SymbolicInst:
-		delete symbolic.name;
-		delete symbolic.params;
-		delete symbolic.actuals;
-		delete symbolic.assertions;
-		break;
-	case Tuple:
-		delete tuple;
-		break;
-	case Typeof:
-	case Basetypeof:
-		delete typeexpr;
-		break;
-	case Vtable:
-	case Builtin:
-		// No unique data to deconstruct.
-		break;
-	case Qualified:
-		delete qualified.parent;
-		delete qualified.child;
-		break;
-	} // switch
-} // TypeData::~TypeData
-
-
-TypeData * TypeData::clone() const {
-	TypeData * newtype = new TypeData( kind );
-	newtype->qualifiers = qualifiers;
-	newtype->base = maybeCopy( base );
-	newtype->forall = maybeCopy( forall );
-
-	switch ( kind ) {
-	case Unknown:
-	case EnumConstant:
-	case Pointer:
-	case Reference:
-	case GlobalScope:
-		// nothing else to copy
-		break;
-	case Basic:
-		newtype->basictype = basictype;
-		newtype->complextype = complextype;
-		newtype->signedness = signedness;
-		newtype->length = length;
-		break;
-	case Array:
-		newtype->array.dimension = maybeCopy( array.dimension );
-		newtype->array.isVarLen = array.isVarLen;
-		newtype->array.isStatic = array.isStatic;
-		break;
-	case Function:
-		newtype->function.params = maybeCopy( function.params );
-		newtype->function.idList = maybeCopy( function.idList );
-		newtype->function.oldDeclList = maybeCopy( function.oldDeclList );
-		newtype->function.body = maybeCopy( function.body );
-		newtype->function.withExprs = maybeCopy( function.withExprs );
-		break;
-	case Aggregate:
-		newtype->aggregate.kind = aggregate.kind;
-		newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
-		newtype->aggregate.params = maybeCopy( aggregate.params );
-		newtype->aggregate.actuals = maybeCopy( aggregate.actuals );
-		newtype->aggregate.fields = maybeCopy( aggregate.fields );
-		newtype->aggregate.attributes = aggregate.attributes;
-		newtype->aggregate.body = aggregate.body;
-		newtype->aggregate.anon = aggregate.anon;
-		break;
-	case AggregateInst:
-		newtype->aggInst.aggregate = maybeCopy( aggInst.aggregate );
-		newtype->aggInst.params = maybeCopy( aggInst.params );
-		newtype->aggInst.hoistType = aggInst.hoistType;
-		break;
-	case Symbolic:
-	case SymbolicInst:
-		newtype->symbolic.name = symbolic.name ? new string( *symbolic.name ) : nullptr;
-		newtype->symbolic.params = maybeCopy( symbolic.params );
-		newtype->symbolic.actuals = maybeCopy( symbolic.actuals );
-		newtype->symbolic.assertions = maybeCopy( symbolic.assertions );
-		newtype->symbolic.isTypedef = symbolic.isTypedef;
-		break;
-	case Tuple:
-		newtype->tuple = maybeCopy( tuple );
-		break;
-	case Typeof:
-	case Basetypeof:
-		newtype->typeexpr = maybeCopy( typeexpr );
-		break;
-	case Vtable:
-		break;
-	case Builtin:
-		assert( builtintype == Zero || builtintype == One );
-		newtype->builtintype = builtintype;
-		break;
-	case Qualified:
-		newtype->qualified.parent = maybeCopy( qualified.parent );
-		newtype->qualified.child = maybeCopy( qualified.child );
-		break;
-	} // switch
-	return newtype;
-} // TypeData::clone
-
-
-void TypeData::print( ostream &os, int indent ) const {
-	ast::print( os, qualifiers );
-
-	if ( forall ) {
-		os << "forall " << endl;
-		forall->printList( os, indent + 4 );
-	} // if
-
-	switch ( kind ) {
-	case Basic:
-		if ( signedness != NoSignedness ) os << signednessNames[ signedness ] << " ";
-		if ( length != NoLength ) os << lengthNames[ length ] << " ";
-		if ( complextype != NoComplexType ) os << complexTypeNames[ complextype ] << " ";
-		if ( basictype != NoBasicType ) os << basicTypeNames[ basictype ] << " ";
-		break;
-	case Pointer:
-		os << "pointer ";
-		if ( base ) {
-			os << "to ";
-			base->print( os, indent );
-		} // if
-		break;
-	case Reference:
-		os << "reference ";
-		if ( base ) {
-			os << "to ";
-			base->print( os, indent );
-		} // if
-		break;
-	case Array:
-		if ( array.isStatic ) {
-			os << "static ";
-		} // if
-		if ( array.dimension ) {
-			os << "array of ";
-			array.dimension->printOneLine( os, indent );
-		} else if ( array.isVarLen ) {
-			os << "variable-length array of ";
-		} else {
-			os << "open array of ";
-		} // if
-		if ( base ) {
-			base->print( os, indent );
-		} // if
-		break;
-	case Function:
-		os << "function" << endl;
-		if ( function.params ) {
-			os << string( indent + 2, ' ' ) << "with parameters " << endl;
-			function.params->printList( os, indent + 4 );
-		} else {
-			os << string( indent + 2, ' ' ) << "with no parameters" << endl;
-		} // if
-		if ( function.idList ) {
-			os << string( indent + 2, ' ' ) << "with old-style identifier list " << endl;
-			function.idList->printList( os, indent + 4 );
-		} // if
-		if ( function.oldDeclList ) {
-			os << string( indent + 2, ' ' ) << "with old-style declaration list " << endl;
-			function.oldDeclList->printList( os, indent + 4 );
-		} // if
-		os << string( indent + 2, ' ' ) << "returning ";
-		if ( base ) {
-			base->print( os, indent + 4 );
-		} else {
-			os << "nothing ";
-		} // if
-		os << endl;
-		if ( function.body ) {
-			os << string( indent + 2, ' ' ) << "with body " << endl;
-			function.body->printList( os, indent + 2 );
-		} // if
-		break;
-	case Aggregate:
-		os << ast::AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
-		if ( aggregate.params ) {
-			os << string( indent + 2, ' ' ) << "with type parameters" << endl;
-			aggregate.params->printList( os, indent + 4 );
-		} // if
-		if ( aggregate.actuals ) {
-			os << string( indent + 2, ' ' ) << "instantiated with actual parameters" << endl;
-			aggregate.actuals->printList( os, indent + 4 );
-		} // if
-		if ( aggregate.fields ) {
-			os << string( indent + 2, ' ' ) << "with members" << endl;
-			aggregate.fields->printList( os, indent + 4 );
-		} // if
-		if ( aggregate.body ) {
-			os << string( indent + 2, ' ' ) << "with body" << endl;
-		} // if
-		if ( ! aggregate.attributes.empty() ) {
-			os << string( indent + 2, ' ' ) << "with attributes" << endl;
-			for ( ast::ptr<ast::Attribute> const & attr : reverseIterate( aggregate.attributes ) ) {
-				os << string( indent + 4, ' ' );
-				ast::print( os, attr, indent + 2 );
-			} // for
-		} // if
-		break;
-	case AggregateInst:
-		if ( aggInst.aggregate ) {
-			os << "instance of " ;
-			aggInst.aggregate->print( os, indent );
-		} else {
-			os << "instance of an unspecified aggregate ";
-		} // if
-		if ( aggInst.params ) {
-			os << string( indent + 2, ' ' ) << "with parameters" << endl;
-			aggInst.params->printList( os, indent + 2 );
-		} // if
-		break;
-	case EnumConstant:
-		os << "enumeration constant ";
-		break;
-	case Symbolic:
-		if ( symbolic.isTypedef ) {
-			os << "typedef definition ";
-		} else {
-			os << "type definition ";
-		} // if
-		if ( symbolic.params ) {
-			os << endl << string( indent + 2, ' ' ) << "with parameters" << endl;
-			symbolic.params->printList( os, indent + 2 );
-		} // if
-		if ( symbolic.assertions ) {
-			os << endl << string( indent + 2, ' ' ) << "with assertions" << endl;
-			symbolic.assertions->printList( os, indent + 4 );
-			os << string( indent + 2, ' ' );
-		} // if
-		if ( base ) {
-			os << "for ";
-			base->print( os, indent + 2 );
-		} // if
-		break;
-	case SymbolicInst:
-		os << *symbolic.name;
-		if ( symbolic.actuals ) {
-			os << "(";
-			symbolic.actuals->printList( os, indent + 2 );
-			os << ")";
-		} // if
-		break;
-	case Tuple:
-		os << "tuple ";
-		if ( tuple ) {
-			os << "with members" << endl;
-			tuple->printList( os, indent + 2 );
-		} // if
-		break;
-	case Basetypeof:
-		os << "base-";
-		#if defined(__GNUC__) && __GNUC__ >= 7
-			__attribute__((fallthrough));
-		#endif
-		// FALL THROUGH
-	case Typeof:
-		os << "type-of expression ";
-		if ( typeexpr ) {
-			typeexpr->print( os, indent + 2 );
-		} // if
-		break;
-	case Vtable:
-		os << "vtable";
-		break;
-	case Builtin:
-		os << builtinTypeNames[builtintype];
-		break;
-	case GlobalScope:
-		break;
-	case Qualified:
-		qualified.parent->print( os );
-		os << ".";
-		qualified.child->print( os );
-		break;
-	case Unknown:
-		os << "entity of unknown type ";
-		break;
-	default:
-		os << "internal error: TypeData::print " << kind << endl;
-		assert( false );
-	} // switch
-} // TypeData::print
-
-const std::string * TypeData::leafName() const {
-	switch ( kind ) {
-	case Unknown:
-	case Pointer:
-	case Reference:
-	case EnumConstant:
-	case GlobalScope:
-	case Array:
-	case Basic:
-	case Function:
-	case AggregateInst:
-	case Tuple:
-	case Typeof:
-	case Basetypeof:
-	case Builtin:
-	case Vtable:
-		assertf(false, "Tried to get leaf name from kind without a name: %d", kind);
-		break;
-	case Aggregate:
-		return aggregate.name;
-	case Symbolic:
-	case SymbolicInst:
-		return symbolic.name;
-	case Qualified:
-		return qualified.child->leafName();
-	} // switch
-	assert(false);
-}
-
-TypeData * TypeData::getLastBase() {
-	TypeData * cur = this;
-	while ( cur->base ) cur = cur->base;
-	return cur;
-}
-
-void TypeData::setLastBase( TypeData * newBase ) {
-	getLastBase()->base = newBase;
-}
-
-
-// Wrap an aggregate up in an instance. Takes and gives ownership.
-static TypeData * makeInstance( TypeData * type ) {
-	assert( TypeData::Aggregate == type->kind );
-	TypeData * out = new TypeData( TypeData::AggregateInst );
-	out->aggInst.aggregate = type;
-	out->aggInst.params = maybeCopy( type->aggregate.actuals );
-	out->aggInst.hoistType = type->aggregate.body;
-	out->qualifiers |= type->qualifiers;
-	return out;
-}
-
-
-TypeData * build_type_qualifier( ast::CV::Qualifiers tq ) {
-	TypeData * type = new TypeData;
-	type->qualifiers = tq;
-	return type;
-}
-
-TypeData * build_basic_type( TypeData::BasicType basic ) {
-	TypeData * type = new TypeData( TypeData::Basic );
-	type->basictype = basic;
-	return type;
-}
-
-TypeData * build_complex_type( TypeData::ComplexType complex ) {
-	TypeData * type = new TypeData( TypeData::Basic );
-	type->complextype = complex;
-	return type;
-}
-
-TypeData * build_signedness( TypeData::Signedness signedness ) {
-	TypeData * type = new TypeData( TypeData::Basic );
-	type->signedness = signedness;
-	return type;
-}
-
-TypeData * build_builtin_type( TypeData::BuiltinType bit ) {
-	TypeData * type = new TypeData( TypeData::Builtin );
-	type->builtintype = bit;
-	return type;
-}
-
-TypeData * build_length( TypeData::Length length ) {
-	TypeData * type = new TypeData( TypeData::Basic );
-	type->length = length;
-	return type;
-}
-
-TypeData * build_forall( DeclarationNode * forall ) {
-	TypeData * type = new TypeData( TypeData::Unknown );
-	type->forall = forall;
-	return type;
-}
-
-TypeData * build_global_scope() {
-	return new TypeData( TypeData::GlobalScope );
-}
-
-TypeData * build_qualified_type( TypeData * parent, TypeData * child ) {
-	TypeData * type = new TypeData( TypeData::Qualified );
-	type->qualified.parent = parent;
-	type->qualified.child = child;
-	return type;
-}
-
-TypeData * build_typedef( const std::string * name ) {
-	TypeData * type = new TypeData( TypeData::SymbolicInst );
-	type->symbolic.name = name;
-	type->symbolic.isTypedef = true;
-	type->symbolic.actuals = nullptr;
-	return type;
-}
-
-TypeData * build_type_gen( const std::string * name, ExpressionNode * params ) {
-	TypeData * type = new TypeData( TypeData::SymbolicInst );
-	type->symbolic.name = name;
-	type->symbolic.isTypedef = false;
-	type->symbolic.actuals = params;
-	return type;
-}
-
-TypeData * build_vtable_type( TypeData * base ) {
-	TypeData * type = new TypeData( TypeData::Vtable );
-	type->base = base;
-	return type;
-}
-
-// Takes ownership of src.
-static void addQualifiersToType( TypeData * dst, TypeData * src ) {
-	if ( dst->base ) {
-		addQualifiersToType( dst->base, src );
-	} else if ( dst->kind == TypeData::Function ) {
-		dst->base = src;
-		src = nullptr;
-    } else {
-		dst->qualifiers |= src->qualifiers;
-		delete src;
-	} // if
-}
-
-// Takes ownership of all arguments, gives ownership of return value.
-TypeData * addQualifiers( TypeData * dst, TypeData * src ) {
-	if ( src->forall ) {
-		if ( dst->forall || TypeData::Aggregate != dst->kind ) {
-			extend( dst->forall, src->forall );
-		} else {
-			extend( dst->aggregate.params, src->forall );
-		}
-		src->forall = nullptr;
-	}
-
-	addQualifiersToType( dst, src );
-	return dst;
-}
-
-// Helper for addType and cloneBaseType.
-static void addTypeToType( TypeData *& dst, TypeData *& src ) {
-	if ( src->forall && dst->kind == TypeData::Function ) {
-		extend( dst->forall, src->forall );
-		src->forall = nullptr;
-	} // if
-	if ( dst->base ) {
-		addTypeToType( dst->base, src );
-		return;
-	}
-	switch ( dst->kind ) {
-	case TypeData::Unknown:
-		src->qualifiers |= dst->qualifiers;
-		// LEAKS dst?
-		dst = src;
-		src = nullptr;
-		break;
-	case TypeData::Basic:
-		dst->qualifiers |= src->qualifiers;
-		if ( src->kind != TypeData::Unknown ) {
-			assert( src->kind == TypeData::Basic );
-
-			if ( dst->basictype == TypeData::NoBasicType ) {
-				dst->basictype = src->basictype;
-			} else if ( src->basictype != TypeData::NoBasicType ) {
-				SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
-					TypeData::basicTypeNames[ dst->basictype ],
-					TypeData::basicTypeNames[ src->basictype ] );
-			}
-			if ( dst->complextype == TypeData::NoComplexType ) {
-				dst->complextype = src->complextype;
-			} else if ( src->complextype != TypeData::NoComplexType ) {
-				SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
-					TypeData::complexTypeNames[ src->complextype ],
-					TypeData::complexTypeNames[ src->complextype ] );
-			}
-			if ( dst->signedness == TypeData::NoSignedness ) {
-				dst->signedness = src->signedness;
-			} else if ( src->signedness != TypeData::NoSignedness ) {
-				SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
-					TypeData::signednessNames[ dst->signedness ],
-					TypeData::signednessNames[ src->signedness ] );
-			}
-			if ( dst->length == TypeData::NoLength ) {
-				dst->length = src->length;
-			} else if ( dst->length == TypeData::Long && src->length == TypeData::Long ) {
-				dst->length = TypeData::LongLong;
-			} else if ( src->length != TypeData::NoLength ) {
-				SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
-					TypeData::lengthNames[ dst->length ],
-					TypeData::lengthNames[ src->length ] );
-			}
-		} // if
-		break;
-	default:
-		if ( TypeData::Aggregate == src->kind ) {
-			dst->base = makeInstance( src );
-		} else {
-			extend( dst->forall, src->forall );
-			src->forall = nullptr;
-			dst->base = src;
-		}
-		src = nullptr;
-	} // switch
-}
-
-// Takes ownership of all arguments, gives ownership of return value.
-TypeData * addType( TypeData * dst, TypeData * src, std::vector<ast::ptr<ast::Attribute>> & attributes ) {
-	if ( dst ) {
-		addTypeToType( dst, src );
-	} else if ( src->kind == TypeData::Aggregate ) {
-		// Hide type information aggregate instances.
-		dst = makeInstance( src );
-		dst->aggInst.aggregate->aggregate.attributes.swap( attributes );
-	} else {
-		dst = src;
-	} // if
-	return dst;
-}
-
-TypeData * addType( TypeData * dst, TypeData * src ) {
-	std::vector<ast::ptr<ast::Attribute>> attributes;
-	return addType( dst, src, attributes );
-}
-
-// Takes ownership of both arguments, gives ownership of return value.
-TypeData * cloneBaseType( TypeData * type, TypeData * other ) {
-	TypeData * newType = type->getLastBase()->clone();
-	if ( newType->kind == TypeData::AggregateInst ) {
-		// don't duplicate members
-		assert( newType->aggInst.aggregate->kind == TypeData::Aggregate );
-		delete newType->aggInst.aggregate->aggregate.fields;
-		newType->aggInst.aggregate->aggregate.fields = nullptr;
-		newType->aggInst.aggregate->aggregate.body = false;
-		// don't hoist twice
-		newType->aggInst.hoistType = false;
-	} // if
-	newType->forall = maybeCopy( type->forall );
-
-	if ( other ) {
-		addTypeToType( other, newType );
-		delete newType;
-		return other;
-	} // if
-	return newType;
-}
-
-TypeData * makeNewBase( TypeData * type ) {
-	return ( TypeData::Aggregate == type->kind ) ? makeInstance( type ) : type;
-}
-
-
-void buildForall(
-		const DeclarationNode * firstNode,
-		std::vector<ast::ptr<ast::TypeInstType>> &outputList ) {
-	{
-		std::vector<ast::ptr<ast::Type>> tmpList;
-		buildTypeList( firstNode, tmpList );
-		for ( auto tmp : tmpList ) {
-			outputList.emplace_back(
-				strict_dynamic_cast<const ast::TypeInstType *>(
-					tmp.release() ) );
-		}
-	}
-	auto n = firstNode;
-	for ( auto i = outputList.begin() ;
-			i != outputList.end() ;
-			++i, n = n->next ) {
-		// Only the object type class adds additional assertions.
-		if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
-			continue;
-		}
-
-		ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>();
-		std::vector<ast::ptr<ast::DeclWithType>> newAssertions;
-		auto mutTypeDecl = ast::mutate( td );
-		const CodeLocation & location = mutTypeDecl->location;
-		*i = mutTypeDecl;
-
-		// add assertion parameters to `type' tyvars in reverse order
-		// add assignment operator:  T * ?=?(T *, T)
-		newAssertions.push_back( new ast::FunctionDecl(
-			location,
-			"?=?",
-			{}, // forall
-			{}, // assertions
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::ReferenceType( i->get() ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-				new ast::ObjectDecl(
-					location,
-					"",
-					i->get(),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // params
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					i->get(),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // returns
-			(ast::CompoundStmt *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-
-		// add default ctor:  void ?{}(T *)
-		newAssertions.push_back( new ast::FunctionDecl(
-			location,
-			"?{}",
-			{}, // forall
-			{}, // assertions
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::ReferenceType( i->get() ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // params
-			{}, // returns
-			(ast::CompoundStmt *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-
-		// add copy ctor:  void ?{}(T *, T)
-		newAssertions.push_back( new ast::FunctionDecl(
-			location,
-			"?{}",
-			{}, // forall
-			{}, // assertions
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::ReferenceType( i->get() ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-				new ast::ObjectDecl(
-					location,
-					"",
-					i->get(),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // params
-			{}, // returns
-			(ast::CompoundStmt *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-
-		// add dtor:  void ^?{}(T *)
-		newAssertions.push_back( new ast::FunctionDecl(
-			location,
-			"^?{}",
-			{}, // forall
-			{}, // assertions
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::ReferenceType( i->get() ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // params
-			{}, // returns
-			(ast::CompoundStmt *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-
-		spliceBegin( mutTypeDecl->assertions, newAssertions );
-	} // for
-}
-
-
-void buildForall(
-		const DeclarationNode * firstNode,
-		std::vector<ast::ptr<ast::TypeDecl>> &outputForall ) {
-	buildList( firstNode, outputForall );
-	auto n = firstNode;
-	for ( auto i = outputForall.begin() ;
-			i != outputForall.end() ;
-			++i, n = n->next ) {
-		// Only the object type class adds additional assertions.
-		if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
-			continue;
-		}
-
-		ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>();
-		std::vector<ast::ptr<ast::DeclWithType>> newAssertions;
-		auto mutTypeDecl = ast::mutate( td );
-		const CodeLocation & location = mutTypeDecl->location;
-		*i = mutTypeDecl;
-
-		// add assertion parameters to `type' tyvars in reverse order
-		// add assignment operator:  T * ?=?(T *, T)
-		newAssertions.push_back( new ast::FunctionDecl(
-			location,
-			"?=?",
-			{}, // forall
-			{}, // assertions
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::ReferenceType( new ast::TypeInstType( td->name, *i ) ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::TypeInstType( td->name, *i ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // params
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::TypeInstType( td->name, *i ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // returns
-			(ast::CompoundStmt *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-
-		// add default ctor:  void ?{}(T *)
-		newAssertions.push_back( new ast::FunctionDecl(
-			location,
-			"?{}",
-			{}, // forall
-			{}, // assertions
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::ReferenceType(
-						new ast::TypeInstType( td->name, i->get() ) ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // params
-			{}, // returns
-			(ast::CompoundStmt *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-
-		// add copy ctor:  void ?{}(T *, T)
-		newAssertions.push_back( new ast::FunctionDecl(
-			location,
-			"?{}",
-			{}, // forall
-			{}, // assertions
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::ReferenceType(
-						new ast::TypeInstType( td->name, *i ) ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::TypeInstType( td->name, *i ),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // params
-			{}, // returns
-			(ast::CompoundStmt *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-
-		// add dtor:  void ^?{}(T *)
-		newAssertions.push_back( new ast::FunctionDecl(
-			location,
-			"^?{}",
-			{}, // forall
-			{}, // assertions
-			{
-				new ast::ObjectDecl(
-					location,
-					"",
-					new ast::ReferenceType(
-						new ast::TypeInstType( i->get() )
-					),
-					(ast::Init *)nullptr,
-					ast::Storage::Classes(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr
-				),
-			}, // params
-			{}, // returns
-			(ast::CompoundStmt *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-
-		spliceBegin( mutTypeDecl->assertions, newAssertions );
-	} // for
-} // buildForall
-
-
-ast::Type * typebuild( const TypeData * td ) {
-	assert( td );
-	switch ( td->kind ) {
-	case TypeData::Unknown:
-		// fill in implicit int
-		return new ast::BasicType(
-			ast::BasicKind::SignedInt,
-			buildQualifiers( td )
-		);
-	case TypeData::Basic:
-		return buildBasicType( td );
-	case TypeData::Pointer:
-		return buildPointer( td );
-	case TypeData::Array:
-		return buildArray( td );
-	case TypeData::Reference:
-		return buildReference( td );
-	case TypeData::Function:
-		return buildFunctionType( td );
-	case TypeData::AggregateInst:
-		return buildAggInst( td );
-	case TypeData::EnumConstant:
-		return new ast::EnumInstType( "", buildQualifiers( td ) );
-	case TypeData::SymbolicInst:
-		return buildSymbolicInst( td );
-	case TypeData::Tuple:
-		return buildTuple( td );
-	case TypeData::Typeof:
-	case TypeData::Basetypeof:
-		return buildTypeof( td );
-	case TypeData::Vtable:
-		return buildVtable( td );
-	case TypeData::Builtin:
-		switch ( td->builtintype ) {
-		case TypeData::Zero:
-			return new ast::ZeroType();
-		case TypeData::One:
-			return new ast::OneType();
-		default:
-			return new ast::VarArgsType( buildQualifiers( td ) );
-		} // switch
-	case TypeData::GlobalScope:
-		return new ast::GlobalScopeType();
-	case TypeData::Qualified:
-		return new ast::QualifiedType(
-			typebuild( td->qualified.parent ),
-			typebuild( td->qualified.child ),
-			buildQualifiers( td )
-		);
-	case TypeData::Symbolic:
-	case TypeData::Aggregate:
-		assert( false );
-	} // switch
-
-	return nullptr;
-} // typebuild
-
-
-TypeData * typeextractAggregate( const TypeData * td, bool toplevel ) {
-	TypeData * ret = nullptr;
-
-	switch ( td->kind ) {
-	case TypeData::Aggregate:
-		if ( ! toplevel && td->aggregate.body ) {
-			ret = td->clone();
-		} // if
-		break;
-	case TypeData::AggregateInst:
-		if ( td->aggInst.aggregate ) {
-			ret = typeextractAggregate( td->aggInst.aggregate, false );
-		} // if
-		break;
-	default:
-		if ( td->base ) {
-			ret = typeextractAggregate( td->base, false );
-		} // if
-	} // switch
-	return ret;
-} // typeextractAggregate
-
-
-ast::CV::Qualifiers buildQualifiers( const TypeData * td ) {
-	return td->qualifiers;
-} // buildQualifiers
-
-
-static string genTSError( string msg, TypeData::BasicType basictype ) {
-	SemanticError( yylloc, "invalid type specifier \"%s\" for type \"%s\".", msg.c_str(), TypeData::basicTypeNames[basictype] );
-} // genTSError
-
-ast::Type * buildBasicType( const TypeData * td ) {
-	ast::BasicKind ret;
-
-	switch ( td->basictype ) {
-	case TypeData::Void:
-		if ( td->signedness != TypeData::NoSignedness ) {
-			genTSError( TypeData::signednessNames[ td->signedness ], td->basictype );
-		} // if
-		if ( td->length != TypeData::NoLength ) {
-			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
-		} // if
-		return new ast::VoidType( buildQualifiers( td ) );
-		break;
-
-	case TypeData::Bool:
-		if ( td->signedness != TypeData::NoSignedness ) {
-			genTSError( TypeData::signednessNames[ td->signedness ], td->basictype );
-		} // if
-		if ( td->length != TypeData::NoLength ) {
-			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
-		} // if
-
-		ret = ast::BasicKind::Bool;
-		break;
-
-	case TypeData::Char:
-		// C11 Standard 6.2.5.15: The three types char, signed char, and unsigned char are collectively called the
-		// character types. The implementation shall define char to have the same range, representation, and behavior as
-		// either signed char or unsigned char.
-		static ast::BasicKind chartype[] = { ast::BasicKind::SignedChar, ast::BasicKind::UnsignedChar, ast::BasicKind::Char };
-
-		if ( td->length != TypeData::NoLength ) {
-			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
-		} // if
-
-		ret = chartype[ td->signedness ];
-		break;
-
-	case TypeData::Int:
-		static ast::BasicKind inttype[2][4] = {
-			{ ast::BasicKind::ShortSignedInt, ast::BasicKind::LongSignedInt, ast::BasicKind::LongLongSignedInt, ast::BasicKind::SignedInt },
-			{ ast::BasicKind::ShortUnsignedInt, ast::BasicKind::LongUnsignedInt, ast::BasicKind::LongLongUnsignedInt, ast::BasicKind::UnsignedInt },
-		};
-
-	Integral: ;
-		if ( td->signedness == TypeData::NoSignedness ) {
-			const_cast<TypeData *>(td)->signedness = TypeData::Signed;
-		} // if
-		ret = inttype[ td->signedness ][ td->length ];
-		break;
-
-	case TypeData::Int128:
-		ret = td->signedness == TypeData::Unsigned ? ast::BasicKind::UnsignedInt128 : ast::BasicKind::SignedInt128;
-		if ( td->length != TypeData::NoLength ) {
-			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
-		} // if
-		break;
-
-	case TypeData::Float:
-	case TypeData::Double:
-	case TypeData::LongDouble:					// not set until below
-	case TypeData::uuFloat80:
-	case TypeData::uuFloat128:
-	case TypeData::uFloat16:
-	case TypeData::uFloat32:
-	case TypeData::uFloat32x:
-	case TypeData::uFloat64:
-	case TypeData::uFloat64x:
-	case TypeData::uFloat128:
-	case TypeData::uFloat128x:
-		static ast::BasicKind floattype[2][12] = {
-			{ ast::BasicKind::FloatComplex, ast::BasicKind::DoubleComplex, ast::BasicKind::LongDoubleComplex, (ast::BasicKind)-1, (ast::BasicKind)-1, ast::BasicKind::uFloat16Complex, ast::BasicKind::uFloat32Complex, ast::BasicKind::uFloat32xComplex, ast::BasicKind::uFloat64Complex, ast::BasicKind::uFloat64xComplex, ast::BasicKind::uFloat128Complex, ast::BasicKind::uFloat128xComplex, },
-			{ ast::BasicKind::Float, ast::BasicKind::Double, ast::BasicKind::LongDouble, ast::BasicKind::uuFloat80, ast::BasicKind::uuFloat128, ast::BasicKind::uFloat16, ast::BasicKind::uFloat32, ast::BasicKind::uFloat32x, ast::BasicKind::uFloat64, ast::BasicKind::uFloat64x, ast::BasicKind::uFloat128, ast::BasicKind::uFloat128x, },
-		};
-
-	FloatingPoint: ;
-		if ( td->signedness != TypeData::NoSignedness ) {
-			genTSError( TypeData::signednessNames[ td->signedness ], td->basictype );
-		} // if
-		if ( td->length == TypeData::Short || td->length == TypeData::LongLong ) {
-			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
-		} // if
-		if ( td->basictype != TypeData::Double && td->length == TypeData::Long ) {
-			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
-		} // if
-		if ( td->complextype == TypeData::Imaginary ) {
-			genTSError( TypeData::complexTypeNames[ td->complextype ], td->basictype );
-		} // if
-		if ( (td->basictype == TypeData::uuFloat80 || td->basictype == TypeData::uuFloat128) && td->complextype == TypeData::Complex ) { // gcc unsupported
-			genTSError( TypeData::complexTypeNames[ td->complextype ], td->basictype );
-		} // if
-		if ( td->length == TypeData::Long ) {
-			const_cast<TypeData *>(td)->basictype = TypeData::LongDouble;
-		} // if
-
-		ret = floattype[ td->complextype ][ td->basictype - TypeData::Float ];
-		//printf( "XXXX %d %d %d %d\n", td->complextype, td->basictype, TypeData::Float, ret );
-		break;
-
-	case TypeData::NoBasicType:
-		// No basic type in declaration => default double for Complex/Imaginary and int type for integral types
-		if ( td->complextype == TypeData::Complex || td->complextype == TypeData::Imaginary ) {
-			const_cast<TypeData *>(td)->basictype = TypeData::Double;
-			goto FloatingPoint;
-		} // if
-
-		const_cast<TypeData *>(td)->basictype = TypeData::Int;
-		goto Integral;
-	default:
-		assertf( false, "unknown basic type" );
-		return nullptr;
-	} // switch
-
-	ast::BasicType * bt = new ast::BasicType( ret, buildQualifiers( td ) );
-	return bt;
-} // buildBasicType
-
-
-static ast::Type * buildDefaultType( const TypeData * td ) {
-	return ( td ) ? typebuild( td ) : new ast::BasicType( ast::BasicKind::SignedInt );
-} // buildDefaultType
-
-
-ast::PointerType * buildPointer( const TypeData * td ) {
-	return new ast::PointerType(
-		buildDefaultType( td->base ),
-		buildQualifiers( td )
-	);
-} // buildPointer
-
-
-ast::ArrayType * buildArray( const TypeData * td ) {
-	return new ast::ArrayType(
-		buildDefaultType( td->base ),
-		maybeBuild( td->array.dimension ),
-		td->array.isVarLen ? ast::VariableLen : ast::FixedLen,
-		td->array.isStatic ? ast::StaticDim : ast::DynamicDim,
-		buildQualifiers( td )
-	);
-} // buildArray
-
-
-ast::ReferenceType * buildReference( const TypeData * td ) {
-	return new ast::ReferenceType(
-		buildDefaultType( td->base ),
-		buildQualifiers( td )
-	);
-} // buildReference
-
-
-ast::AggregateDecl * buildAggregate( const TypeData * td, std::vector<ast::ptr<ast::Attribute>> attributes, ast::Linkage::Spec linkage ) {
-	assert( td->kind == TypeData::Aggregate );
-	ast::AggregateDecl * at;
-	switch ( td->aggregate.kind ) {
-	case ast::AggregateDecl::Struct:
-	case ast::AggregateDecl::Coroutine:
-	case ast::AggregateDecl::Exception:
-	case ast::AggregateDecl::Generator:
-	case ast::AggregateDecl::Monitor:
-	case ast::AggregateDecl::Thread:
-		at = new ast::StructDecl( td->location,
-			*td->aggregate.name,
-			td->aggregate.kind,
-			std::move( attributes ),
-			linkage
-		);
-		buildForall( td->aggregate.params, at->params );
-		break;
-	case ast::AggregateDecl::Union:
-		at = new ast::UnionDecl( td->location,
-			*td->aggregate.name,
-			std::move( attributes ),
-			linkage
-		);
-		buildForall( td->aggregate.params, at->params );
-		break;
-	case ast::AggregateDecl::Enum:
-		return buildEnum( td, std::move( attributes ), linkage );
-	case ast::AggregateDecl::Trait:
-		at = new ast::TraitDecl( td->location,
-			*td->aggregate.name,
-			std::move( attributes ),
-			linkage
-		);
-		buildList( td->aggregate.params, at->params );
-		break;
-	default:
-		assert( false );
-	} // switch
-
-	buildList( td->aggregate.fields, at->members );
-	at->set_body( td->aggregate.body );
-
-	return at;
-} // buildAggregate
-
-
-ast::BaseInstType * buildComAggInst(
-		const TypeData * td,
-		std::vector<ast::ptr<ast::Attribute>> && attributes,
-		ast::Linkage::Spec linkage ) {
-	switch ( td->kind ) {
-	case TypeData::Aggregate:
-		if ( td->aggregate.body ) {
-			ast::AggregateDecl * typedecl =
-				buildAggregate( td, std::move( attributes ), linkage );
-			switch ( td->aggregate.kind ) {
-			case ast::AggregateDecl::Struct:
-			case ast::AggregateDecl::Coroutine:
-			case ast::AggregateDecl::Monitor:
-			case ast::AggregateDecl::Thread:
-				return new ast::StructInstType(
-					strict_dynamic_cast<ast::StructDecl *>( typedecl ),
-					buildQualifiers( td )
-				);
-			case ast::AggregateDecl::Union:
-				return new ast::UnionInstType(
-					strict_dynamic_cast<ast::UnionDecl *>( typedecl ),
-					buildQualifiers( td )
-				);
-			case ast::AggregateDecl::Enum:
-				return new ast::EnumInstType(
-					strict_dynamic_cast<ast::EnumDecl *>( typedecl ),
-					buildQualifiers( td )
-				);
-			case ast::AggregateDecl::Trait:
-				assert( false );
-				break;
-			default:
-				assert( false );
-			} // switch
-		} else {
-			switch ( td->aggregate.kind ) {
-			case ast::AggregateDecl::Struct:
-			case ast::AggregateDecl::Coroutine:
-			case ast::AggregateDecl::Monitor:
-			case ast::AggregateDecl::Thread:
-				return new ast::StructInstType(
-					*td->aggregate.name,
-					buildQualifiers( td )
-				);
-			case ast::AggregateDecl::Union:
-				return new ast::UnionInstType(
-					*td->aggregate.name,
-					buildQualifiers( td )
-				);
-			case ast::AggregateDecl::Enum:
-				return new ast::EnumInstType(
-					*td->aggregate.name,
-					buildQualifiers( td )
-				);
-			case ast::AggregateDecl::Trait:
-				return new ast::TraitInstType(
-					*td->aggregate.name,
-					buildQualifiers( td )
-				);
-			default:
-				assert( false );
-			} // switch
-			break;
-		} // if
-		break;
-	default:
-		assert( false );
-	} // switch
-	assert( false );
-} // buildAggInst
-
-
-ast::BaseInstType * buildAggInst( const TypeData * td ) {
-	assert( td->kind == TypeData::AggregateInst );
-
-	ast::BaseInstType * ret = nullptr;
-	TypeData * type = td->aggInst.aggregate;
-	switch ( type->kind ) {
-	case TypeData::Aggregate:
-		switch ( type->aggregate.kind ) {
-		case ast::AggregateDecl::Struct:
-		case ast::AggregateDecl::Coroutine:
-		case ast::AggregateDecl::Monitor:
-		case ast::AggregateDecl::Thread:
-			ret = new ast::StructInstType(
-				*type->aggregate.name,
-				buildQualifiers( type )
-			);
-			break;
-		case ast::AggregateDecl::Union:
-			ret = new ast::UnionInstType(
-				*type->aggregate.name,
-				buildQualifiers( type )
-			);
-			break;
-		case ast::AggregateDecl::Enum:
-			ret = new ast::EnumInstType(
-				*type->aggregate.name,
-				buildQualifiers( type )
-			);
-			break;
-		case ast::AggregateDecl::Trait:
-			ret = new ast::TraitInstType(
-				*type->aggregate.name,
-				buildQualifiers( type )
-			);
-			break;
-		default:
-			assert( false );
-		} // switch
-		break;
-	default:
-		assert( false );
-	} // switch
-
-	ret->hoistType = td->aggInst.hoistType;
-	buildList( td->aggInst.params, ret->params );
-	return ret;
-} // buildAggInst
-
-
-ast::NamedTypeDecl * buildSymbolic(
-		const TypeData * td,
-		std::vector<ast::ptr<ast::Attribute>> attributes,
-		const std::string & name,
-		ast::Storage::Classes scs,
-		ast::Linkage::Spec linkage ) {
-	assert( td->kind == TypeData::Symbolic );
-	ast::NamedTypeDecl * ret;
-	assert( td->base );
-	if ( td->symbolic.isTypedef ) {
-		ret = new ast::TypedefDecl(
-			td->location,
-			name,
-			scs,
-			typebuild( td->base ),
-			linkage
-		);
-	} else {
-		ret = new ast::TypeDecl(
-			td->location,
-			name,
-			scs,
-			typebuild( td->base ),
-			ast::TypeDecl::Dtype,
-			true
-		);
-	} // if
-	buildList( td->symbolic.assertions, ret->assertions );
-	splice( ret->base.get_and_mutate()->attributes, attributes );
-	return ret;
-} // buildSymbolic
-
-
-ast::EnumDecl * buildEnum(
-		const TypeData * td,
-		std::vector<ast::ptr<ast::Attribute>> && attributes,
-		ast::Linkage::Spec linkage ) {
-	assert( td->kind == TypeData::Aggregate );
-	assert( td->aggregate.kind == ast::AggregateDecl::Enum );
-	ast::Type * baseType = td->base ? typebuild(td->base) : nullptr;
-	ast::EnumDecl * ret = new ast::EnumDecl(
-		td->location,
-		*td->aggregate.name,
-		td->aggregate.typed,
-		std::move( attributes ),
-		linkage,
-		baseType
-	);
-	buildList( td->aggregate.fields, ret->members );
-	auto members = ret->members.begin();
-	ret->hide = td->aggregate.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
-	for ( const DeclarationNode * cur = td->aggregate.fields ; cur != nullptr ; cur = cur->next, ++members ) {
-		if ( cur->enumInLine ) {
-			// Do Nothing
-		} else if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
-			SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
-		} else if ( cur->has_enumeratorValue() ) {
-			ast::Decl * member = members->get_and_mutate();
-			ast::ObjectDecl * object = strict_dynamic_cast<ast::ObjectDecl *>( member );
-			object->init = new ast::SingleInit(
-				td->location,
-				maybeMoveBuild( cur->consume_enumeratorValue() ),
-				ast::NoConstruct
-			);
-		} else if ( !cur->initializer ) {
-			if ( baseType && (!dynamic_cast<ast::BasicType *>(baseType) || !dynamic_cast<ast::BasicType *>(baseType)->isInteger())) {
-				SemanticError( td->location, "Enumerators of an non-integer typed enum must be explicitly initialized." );
-			}
-		}
-		// else cur is a List Initializer and has been set as init in buildList()
-		// if
-	} // for
-	ret->body = td->aggregate.body;
-	return ret;
-} // buildEnum
-
-
-ast::TypeInstType * buildSymbolicInst( const TypeData * td ) {
-	assert( td->kind == TypeData::SymbolicInst );
-	ast::TypeInstType * ret = new ast::TypeInstType(
-		*td->symbolic.name,
-		ast::TypeDecl::Dtype,
-		buildQualifiers( td )
-	);
-	buildList( td->symbolic.actuals, ret->params );
-	return ret;
-} // buildSymbolicInst
-
-
-ast::TupleType * buildTuple( const TypeData * td ) {
-	assert( td->kind == TypeData::Tuple );
-	std::vector<ast::ptr<ast::Type>> types;
-	buildTypeList( td->tuple, types );
-	ast::TupleType * ret = new ast::TupleType(
-		std::move( types ),
-		buildQualifiers( td )
-	);
-	return ret;
-} // buildTuple
-
-
-ast::TypeofType * buildTypeof( const TypeData * td ) {
-	assert( td->kind == TypeData::Typeof || td->kind == TypeData::Basetypeof );
-	assert( td->typeexpr );
-	return new ast::TypeofType(
-		td->typeexpr->build(),
-		td->kind == TypeData::Typeof
-			? ast::TypeofType::Typeof : ast::TypeofType::Basetypeof,
-		buildQualifiers( td )
-	);
-} // buildTypeof
-
-
-ast::VTableType * buildVtable( const TypeData * td ) {
-	assert( td->base );
-	return new ast::VTableType(
-		typebuild( td->base ),
-		buildQualifiers( td )
-	);
-} // buildVtable
-
-
-ast::FunctionDecl * buildFunctionDecl(
-		const TypeData * td,
-		const string &name,
-		ast::Storage::Classes scs,
-		ast::Function::Specs funcSpec,
-		ast::Linkage::Spec linkage,
-		ast::Expr * asmName,
-		std::vector<ast::ptr<ast::Attribute>> && attributes ) {
-	assert( td->kind == TypeData::Function );
-	// For some reason FunctionDecl takes a bool instead of an ArgumentFlag.
-	bool isVarArgs = !td->function.params || td->function.params->hasEllipsis;
-	ast::CV::Qualifiers cvq = buildQualifiers( td );
-	std::vector<ast::ptr<ast::TypeDecl>> forall;
-	std::vector<ast::ptr<ast::DeclWithType>> assertions;
-	std::vector<ast::ptr<ast::DeclWithType>> params;
-	std::vector<ast::ptr<ast::DeclWithType>> returns;
-	buildList( td->function.params, params );
-	buildForall( td->forall, forall );
-	// Functions do not store their assertions there anymore.
-	for ( ast::ptr<ast::TypeDecl> & type_param : forall ) {
-		auto mut = type_param.get_and_mutate();
-		splice( assertions, mut->assertions );
-	}
-	if ( td->base ) {
-		switch ( td->base->kind ) {
-		case TypeData::Tuple:
-			buildList( td->base->tuple, returns );
-			break;
-		default:
-			returns.push_back( dynamic_cast<ast::DeclWithType *>(
-				buildDecl(
-					td->base,
-					"",
-					ast::Storage::Classes(),
-					(ast::Expr *)nullptr, // bitfieldWidth
-					ast::Function::Specs(),
-					ast::Linkage::Cforall,
-					(ast::Expr *)nullptr // asmName
-				)
-			) );
-		} // switch
-	} else {
-		returns.push_back( new ast::ObjectDecl(
-			td->location,
-			"",
-			new ast::BasicType( ast::BasicKind::SignedInt ),
-			(ast::Init *)nullptr,
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
-		) );
-	} // if
-	ast::Stmt * stmt = maybeBuild( td->function.body );
-	ast::CompoundStmt * body = dynamic_cast<ast::CompoundStmt *>( stmt );
-	ast::FunctionDecl * decl = new ast::FunctionDecl( td->location,
-		name,
-		std::move( forall ),
-		std::move( assertions ),
-		std::move( params ),
-		std::move( returns ),
-		body,
-		scs,
-		linkage,
-		std::move( attributes ),
-		funcSpec,
-		(isVarArgs) ? ast::VariableArgs : ast::FixedArgs
-	);
-	buildList( td->function.withExprs, decl->withExprs );
-	decl->asmName = asmName;
-	// This may be redundant on a declaration.
-	decl->type.get_and_mutate()->qualifiers = cvq;
-	return decl;
-} // buildFunctionDecl
-
-
-ast::Decl * buildDecl(
-		const TypeData * td,
-		const string &name,
-		ast::Storage::Classes scs,
-		ast::Expr * bitfieldWidth,
-		ast::Function::Specs funcSpec,
-		ast::Linkage::Spec linkage,
-		ast::Expr * asmName,
-		ast::Init * init,
-		std::vector<ast::ptr<ast::Attribute>> && attributes ) {
-	if ( td->kind == TypeData::Function ) {
-		if ( td->function.idList ) {					// KR function ?
-			buildKRFunction( td->function );			// transform into C11 function
-		} // if
-
-		return buildFunctionDecl(
-			td, name, scs, funcSpec, linkage,
-			asmName, std::move( attributes ) );
-	} else if ( td->kind == TypeData::Aggregate ) {
-		return buildAggregate( td, std::move( attributes ), linkage );
-	} else if ( td->kind == TypeData::Symbolic ) {
-		return buildSymbolic( td, std::move( attributes ), name, scs, linkage );
-	} else {
-		auto ret = new ast::ObjectDecl( td->location,
-			name,
-			typebuild( td ),
-			init,
-			scs,
-			linkage,
-			bitfieldWidth,
-			std::move( attributes )
-		);
-		ret->asmName = asmName;
-		return ret;
-	} // if
-	return nullptr;
-} // buildDecl
-
-
-ast::FunctionType * buildFunctionType( const TypeData * td ) {
-	assert( td->kind == TypeData::Function );
-	ast::FunctionType * ft = new ast::FunctionType(
-		( !td->function.params || td->function.params->hasEllipsis )
-			? ast::VariableArgs : ast::FixedArgs,
-		buildQualifiers( td )
-	);
-	buildTypeList( td->function.params, ft->params );
-	buildForall( td->forall, ft->forall );
-	if ( td->base ) {
-		switch ( td->base->kind ) {
-		case TypeData::Tuple:
-			buildTypeList( td->base->tuple, ft->returns );
-			break;
-		default:
-			ft->returns.push_back( typebuild( td->base ) );
-			break;
-		} // switch
-	} else {
-		ft->returns.push_back(
-			new ast::BasicType( ast::BasicKind::SignedInt ) );
-	} // if
-	return ft;
-} // buildFunctionType
-
-
-// Transform KR routine declarations into C99 routine declarations:
-//
-//    rtn( a, b, c ) int a, c; double b {}  =>  int rtn( int a, double c, int b ) {}
-//
-// The type information for each post-declaration is moved to the corresponding pre-parameter and the post-declaration
-// is deleted. Note, the order of the parameter names may not be the same as the declaration names. Duplicate names and
-// extra names are disallowed.
-//
-// Note, there is no KR routine-prototype syntax:
-//
-//    rtn( a, b, c ) int a, c; double b; // invalid KR prototype
-//    rtn(); // valid KR prototype
-
-void buildKRFunction( const TypeData::Function_t & function ) {
-	assert( ! function.params );
-	// loop over declaration first as it is easier to spot errors
-	for ( DeclarationNode * decl = function.oldDeclList; decl != nullptr; decl = decl->next ) {
-		// scan ALL parameter names for each declaration name to check for duplicates
-		for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
-			if ( *decl->name == *param->name ) {
-				// type set => parameter name already transformed by a declaration names so there is a duplicate
-				// declaration name attempting a second transformation
-				if ( param->type ) SemanticError( param->location, "duplicate declaration name \"%s\".", param->name->c_str() );
-				// declaration type reset => declaration already transformed by a parameter name so there is a duplicate
-				// parameter name attempting a second transformation
-				if ( ! decl->type ) SemanticError( param->location, "duplicate parameter name \"%s\".", param->name->c_str() );
-				param->type = decl->type;				// set copy declaration type to parameter type
-				decl->type = nullptr;					// reset declaration type
-				// Copy and reset attributes from declaration to parameter:
-				splice( param->attributes, decl->attributes );
-			} // if
-		} // for
-		// declaration type still set => type not moved to a matching parameter so there is a missing parameter name
-		if ( decl->type ) SemanticError( decl->location, "missing name in parameter list %s", decl->name->c_str() );
-	} // for
-
-	// Parameter names without a declaration default to type int:
-	//
-	//    rtb( a, b, c ) const char * b; {} => int rtn( int a, const char * b, int c ) {}
-
-	for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
-		if ( ! param->type ) {							// generate type int for empty parameter type
-			param->type = new TypeData( TypeData::Basic );
-			param->type->basictype = TypeData::Int;
-		} // if
-	} // for
-
-	function.params = function.idList;					// newly modified idList becomes parameters
-	function.idList = nullptr;							// idList now empty
-	delete function.oldDeclList;						// deletes entire list
-	function.oldDeclList = nullptr;						// reset
-} // buildKRFunction
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/TypeData.cpp
===================================================================
--- src/Parser/TypeData.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/TypeData.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,1733 @@
+//
+// 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.
+//
+// TypeData.cpp --
+//
+// Author           : Rodolfo G. Esteves
+// Created On       : Sat May 16 15:12:51 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri Feb 23 08:58:30 2024
+// Update Count     : 734
+//
+
+#include "TypeData.hpp"
+
+#include <cassert>                   // for assert
+#include <ostream>                   // for operator<<, ostream, basic_ostream
+
+#include "AST/Attribute.hpp"         // for Attribute
+#include "AST/Decl.hpp"              // for AggregateDecl, ObjectDecl, Type...
+#include "AST/Init.hpp"              // for SingleInit, ListInit
+#include "AST/Print.hpp"             // for print
+#include "AST/Type.hpp"              // for Type
+#include "Common/SemanticError.hpp"  // for SemanticError
+#include "Common/Utility.hpp"        // for splice, spliceBegin
+#include "Common/Iterate.hpp"        // for reverseIterate
+#include "Parser/ExpressionNode.hpp" // for ExpressionNode
+#include "Parser/StatementNode.hpp"  // for StatementNode
+
+class Attribute;
+
+using namespace std;
+
+// These must harmonize with the corresponding enumerations in the header.
+const char * TypeData::basicTypeNames[] = {
+	"void", "_Bool", "char", "int", "int128",
+	"float", "double", "long double", "float80", "float128",
+	"_float16", "_float32", "_float32x", "_float64", "_float64x", "_float128", "_float128x",
+	"NoBasicTypeNames"
+};
+const char * TypeData::complexTypeNames[] = {
+	"_Complex", "NoComplexTypeNames", "_Imaginary"
+}; // Imaginary unsupported => parse, but make invisible and print error message
+const char * TypeData::signednessNames[] = {
+	"signed", "unsigned", "NoSignednessNames"
+};
+const char * TypeData::lengthNames[] = {
+	"short", "long", "long long", "NoLengthNames"
+};
+const char * TypeData::builtinTypeNames[] = {
+	"__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames"
+};
+
+TypeData::TypeData( Kind k ) : location( yylloc ), kind( k ), base( nullptr ), forall( nullptr ) /*, PTR1( (void*)(0xdeadbeefdeadbeef)), PTR2( (void*)(0xdeadbeefdeadbeef) ) */ {
+	switch ( kind ) {
+	case Unknown:
+	case Pointer:
+	case Reference:
+	case EnumConstant:
+	case GlobalScope:
+	case Basic:
+		// No unique data to initialize.
+		break;
+	case Array:
+		array.dimension = nullptr;
+		array.isVarLen = false;
+		array.isStatic = false;
+		break;
+	case Function:
+		function.params = nullptr;
+		function.idList = nullptr;
+		function.oldDeclList = nullptr;
+		function.body = nullptr;
+		function.withExprs = nullptr;
+		break;
+	case Aggregate:
+		aggregate.kind = ast::AggregateDecl::NoAggregate;
+		aggregate.name = nullptr;
+		aggregate.params = nullptr;
+		aggregate.actuals = nullptr;
+		aggregate.fields = nullptr;
+		aggregate.body = false;
+		aggregate.anon = false;
+		aggregate.typed = false;
+		aggregate.hiding = EnumHiding::Visible;
+		break;
+	case AggregateInst:
+		aggInst.aggregate = nullptr;
+		aggInst.params = nullptr;
+		aggInst.hoistType = false;
+		break;
+	case Symbolic:
+	case SymbolicInst:
+		symbolic.name = nullptr;
+		symbolic.params = nullptr;
+		symbolic.actuals = nullptr;
+		symbolic.assertions = nullptr;
+		break;
+	case Tuple:
+		tuple = nullptr;
+		break;
+	case Typeof:
+	case Basetypeof:
+		typeexpr = nullptr;
+		break;
+	case Vtable:
+	case Builtin:
+		// No unique data to initialize.
+		break;
+	case Qualified:
+		qualified.parent = nullptr;
+		qualified.child = nullptr;
+		break;
+	} // switch
+} // TypeData::TypeData
+
+
+TypeData::~TypeData() {
+	delete base;
+	delete forall;
+
+	switch ( kind ) {
+	case Unknown:
+	case Pointer:
+	case Reference:
+	case EnumConstant:
+	case GlobalScope:
+	case Basic:
+		// No unique data to deconstruct.
+		break;
+	case Array:
+		delete array.dimension;
+		break;
+	case Function:
+		delete function.params;
+		delete function.idList;
+		delete function.oldDeclList;
+		delete function.body;
+		delete function.withExprs;
+		break;
+	case Aggregate:
+		delete aggregate.name;
+		delete aggregate.params;
+		delete aggregate.actuals;
+		delete aggregate.fields;
+		break;
+	case AggregateInst:
+		delete aggInst.aggregate;
+		delete aggInst.params;
+		break;
+	case Symbolic:
+	case SymbolicInst:
+		delete symbolic.name;
+		delete symbolic.params;
+		delete symbolic.actuals;
+		delete symbolic.assertions;
+		break;
+	case Tuple:
+		delete tuple;
+		break;
+	case Typeof:
+	case Basetypeof:
+		delete typeexpr;
+		break;
+	case Vtable:
+	case Builtin:
+		// No unique data to deconstruct.
+		break;
+	case Qualified:
+		delete qualified.parent;
+		delete qualified.child;
+		break;
+	} // switch
+} // TypeData::~TypeData
+
+
+TypeData * TypeData::clone() const {
+	TypeData * newtype = new TypeData( kind );
+	newtype->qualifiers = qualifiers;
+	newtype->base = maybeCopy( base );
+	newtype->forall = maybeCopy( forall );
+
+	switch ( kind ) {
+	case Unknown:
+	case EnumConstant:
+	case Pointer:
+	case Reference:
+	case GlobalScope:
+		// nothing else to copy
+		break;
+	case Basic:
+		newtype->basictype = basictype;
+		newtype->complextype = complextype;
+		newtype->signedness = signedness;
+		newtype->length = length;
+		break;
+	case Array:
+		newtype->array.dimension = maybeCopy( array.dimension );
+		newtype->array.isVarLen = array.isVarLen;
+		newtype->array.isStatic = array.isStatic;
+		break;
+	case Function:
+		newtype->function.params = maybeCopy( function.params );
+		newtype->function.idList = maybeCopy( function.idList );
+		newtype->function.oldDeclList = maybeCopy( function.oldDeclList );
+		newtype->function.body = maybeCopy( function.body );
+		newtype->function.withExprs = maybeCopy( function.withExprs );
+		break;
+	case Aggregate:
+		newtype->aggregate.kind = aggregate.kind;
+		newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
+		newtype->aggregate.params = maybeCopy( aggregate.params );
+		newtype->aggregate.actuals = maybeCopy( aggregate.actuals );
+		newtype->aggregate.fields = maybeCopy( aggregate.fields );
+		newtype->aggregate.attributes = aggregate.attributes;
+		newtype->aggregate.body = aggregate.body;
+		newtype->aggregate.anon = aggregate.anon;
+		break;
+	case AggregateInst:
+		newtype->aggInst.aggregate = maybeCopy( aggInst.aggregate );
+		newtype->aggInst.params = maybeCopy( aggInst.params );
+		newtype->aggInst.hoistType = aggInst.hoistType;
+		break;
+	case Symbolic:
+	case SymbolicInst:
+		newtype->symbolic.name = symbolic.name ? new string( *symbolic.name ) : nullptr;
+		newtype->symbolic.params = maybeCopy( symbolic.params );
+		newtype->symbolic.actuals = maybeCopy( symbolic.actuals );
+		newtype->symbolic.assertions = maybeCopy( symbolic.assertions );
+		newtype->symbolic.isTypedef = symbolic.isTypedef;
+		break;
+	case Tuple:
+		newtype->tuple = maybeCopy( tuple );
+		break;
+	case Typeof:
+	case Basetypeof:
+		newtype->typeexpr = maybeCopy( typeexpr );
+		break;
+	case Vtable:
+		break;
+	case Builtin:
+		assert( builtintype == Zero || builtintype == One );
+		newtype->builtintype = builtintype;
+		break;
+	case Qualified:
+		newtype->qualified.parent = maybeCopy( qualified.parent );
+		newtype->qualified.child = maybeCopy( qualified.child );
+		break;
+	} // switch
+	return newtype;
+} // TypeData::clone
+
+
+void TypeData::print( ostream &os, int indent ) const {
+	ast::print( os, qualifiers );
+
+	if ( forall ) {
+		os << "forall " << endl;
+		forall->printList( os, indent + 4 );
+	} // if
+
+	switch ( kind ) {
+	case Basic:
+		if ( signedness != NoSignedness ) os << signednessNames[ signedness ] << " ";
+		if ( length != NoLength ) os << lengthNames[ length ] << " ";
+		if ( complextype != NoComplexType ) os << complexTypeNames[ complextype ] << " ";
+		if ( basictype != NoBasicType ) os << basicTypeNames[ basictype ] << " ";
+		break;
+	case Pointer:
+		os << "pointer ";
+		if ( base ) {
+			os << "to ";
+			base->print( os, indent );
+		} // if
+		break;
+	case Reference:
+		os << "reference ";
+		if ( base ) {
+			os << "to ";
+			base->print( os, indent );
+		} // if
+		break;
+	case Array:
+		if ( array.isStatic ) {
+			os << "static ";
+		} // if
+		if ( array.dimension ) {
+			os << "array of ";
+			array.dimension->printOneLine( os, indent );
+		} else if ( array.isVarLen ) {
+			os << "variable-length array of ";
+		} else {
+			os << "open array of ";
+		} // if
+		if ( base ) {
+			base->print( os, indent );
+		} // if
+		break;
+	case Function:
+		os << "function" << endl;
+		if ( function.params ) {
+			os << string( indent + 2, ' ' ) << "with parameters " << endl;
+			function.params->printList( os, indent + 4 );
+		} else {
+			os << string( indent + 2, ' ' ) << "with no parameters" << endl;
+		} // if
+		if ( function.idList ) {
+			os << string( indent + 2, ' ' ) << "with old-style identifier list " << endl;
+			function.idList->printList( os, indent + 4 );
+		} // if
+		if ( function.oldDeclList ) {
+			os << string( indent + 2, ' ' ) << "with old-style declaration list " << endl;
+			function.oldDeclList->printList( os, indent + 4 );
+		} // if
+		os << string( indent + 2, ' ' ) << "returning ";
+		if ( base ) {
+			base->print( os, indent + 4 );
+		} else {
+			os << "nothing ";
+		} // if
+		os << endl;
+		if ( function.body ) {
+			os << string( indent + 2, ' ' ) << "with body " << endl;
+			function.body->printList( os, indent + 2 );
+		} // if
+		break;
+	case Aggregate:
+		os << ast::AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
+		if ( aggregate.params ) {
+			os << string( indent + 2, ' ' ) << "with type parameters" << endl;
+			aggregate.params->printList( os, indent + 4 );
+		} // if
+		if ( aggregate.actuals ) {
+			os << string( indent + 2, ' ' ) << "instantiated with actual parameters" << endl;
+			aggregate.actuals->printList( os, indent + 4 );
+		} // if
+		if ( aggregate.fields ) {
+			os << string( indent + 2, ' ' ) << "with members" << endl;
+			aggregate.fields->printList( os, indent + 4 );
+		} // if
+		if ( aggregate.body ) {
+			os << string( indent + 2, ' ' ) << "with body" << endl;
+		} // if
+		if ( ! aggregate.attributes.empty() ) {
+			os << string( indent + 2, ' ' ) << "with attributes" << endl;
+			for ( ast::ptr<ast::Attribute> const & attr : reverseIterate( aggregate.attributes ) ) {
+				os << string( indent + 4, ' ' );
+				ast::print( os, attr, indent + 2 );
+			} // for
+		} // if
+		break;
+	case AggregateInst:
+		if ( aggInst.aggregate ) {
+			os << "instance of " ;
+			aggInst.aggregate->print( os, indent );
+		} else {
+			os << "instance of an unspecified aggregate ";
+		} // if
+		if ( aggInst.params ) {
+			os << string( indent + 2, ' ' ) << "with parameters" << endl;
+			aggInst.params->printList( os, indent + 2 );
+		} // if
+		break;
+	case EnumConstant:
+		os << "enumeration constant ";
+		break;
+	case Symbolic:
+		if ( symbolic.isTypedef ) {
+			os << "typedef definition ";
+		} else {
+			os << "type definition ";
+		} // if
+		if ( symbolic.params ) {
+			os << endl << string( indent + 2, ' ' ) << "with parameters" << endl;
+			symbolic.params->printList( os, indent + 2 );
+		} // if
+		if ( symbolic.assertions ) {
+			os << endl << string( indent + 2, ' ' ) << "with assertions" << endl;
+			symbolic.assertions->printList( os, indent + 4 );
+			os << string( indent + 2, ' ' );
+		} // if
+		if ( base ) {
+			os << "for ";
+			base->print( os, indent + 2 );
+		} // if
+		break;
+	case SymbolicInst:
+		os << *symbolic.name;
+		if ( symbolic.actuals ) {
+			os << "(";
+			symbolic.actuals->printList( os, indent + 2 );
+			os << ")";
+		} // if
+		break;
+	case Tuple:
+		os << "tuple ";
+		if ( tuple ) {
+			os << "with members" << endl;
+			tuple->printList( os, indent + 2 );
+		} // if
+		break;
+	case Basetypeof:
+		os << "base-";
+		#if defined(__GNUC__) && __GNUC__ >= 7
+			__attribute__((fallthrough));
+		#endif
+		// FALL THROUGH
+	case Typeof:
+		os << "type-of expression ";
+		if ( typeexpr ) {
+			typeexpr->print( os, indent + 2 );
+		} // if
+		break;
+	case Vtable:
+		os << "vtable";
+		break;
+	case Builtin:
+		os << builtinTypeNames[builtintype];
+		break;
+	case GlobalScope:
+		break;
+	case Qualified:
+		qualified.parent->print( os );
+		os << ".";
+		qualified.child->print( os );
+		break;
+	case Unknown:
+		os << "entity of unknown type ";
+		break;
+	default:
+		os << "internal error: TypeData::print " << kind << endl;
+		assert( false );
+	} // switch
+} // TypeData::print
+
+const std::string * TypeData::leafName() const {
+	switch ( kind ) {
+	case Unknown:
+	case Pointer:
+	case Reference:
+	case EnumConstant:
+	case GlobalScope:
+	case Array:
+	case Basic:
+	case Function:
+	case AggregateInst:
+	case Tuple:
+	case Typeof:
+	case Basetypeof:
+	case Builtin:
+	case Vtable:
+		assertf(false, "Tried to get leaf name from kind without a name: %d", kind);
+		break;
+	case Aggregate:
+		return aggregate.name;
+	case Symbolic:
+	case SymbolicInst:
+		return symbolic.name;
+	case Qualified:
+		return qualified.child->leafName();
+	} // switch
+	assert(false);
+}
+
+TypeData * TypeData::getLastBase() {
+	TypeData * cur = this;
+	while ( cur->base ) cur = cur->base;
+	return cur;
+}
+
+void TypeData::setLastBase( TypeData * newBase ) {
+	getLastBase()->base = newBase;
+}
+
+
+// Wrap an aggregate up in an instance. Takes and gives ownership.
+static TypeData * makeInstance( TypeData * type ) {
+	assert( TypeData::Aggregate == type->kind );
+	TypeData * out = new TypeData( TypeData::AggregateInst );
+	out->aggInst.aggregate = type;
+	out->aggInst.params = maybeCopy( type->aggregate.actuals );
+	out->aggInst.hoistType = type->aggregate.body;
+	out->qualifiers |= type->qualifiers;
+	return out;
+}
+
+
+TypeData * build_type_qualifier( ast::CV::Qualifiers tq ) {
+	TypeData * type = new TypeData;
+	type->qualifiers = tq;
+	return type;
+}
+
+TypeData * build_basic_type( TypeData::BasicType basic ) {
+	TypeData * type = new TypeData( TypeData::Basic );
+	type->basictype = basic;
+	return type;
+}
+
+TypeData * build_complex_type( TypeData::ComplexType complex ) {
+	TypeData * type = new TypeData( TypeData::Basic );
+	type->complextype = complex;
+	return type;
+}
+
+TypeData * build_signedness( TypeData::Signedness signedness ) {
+	TypeData * type = new TypeData( TypeData::Basic );
+	type->signedness = signedness;
+	return type;
+}
+
+TypeData * build_builtin_type( TypeData::BuiltinType bit ) {
+	TypeData * type = new TypeData( TypeData::Builtin );
+	type->builtintype = bit;
+	return type;
+}
+
+TypeData * build_length( TypeData::Length length ) {
+	TypeData * type = new TypeData( TypeData::Basic );
+	type->length = length;
+	return type;
+}
+
+TypeData * build_forall( DeclarationNode * forall ) {
+	TypeData * type = new TypeData( TypeData::Unknown );
+	type->forall = forall;
+	return type;
+}
+
+TypeData * build_global_scope() {
+	return new TypeData( TypeData::GlobalScope );
+}
+
+TypeData * build_qualified_type( TypeData * parent, TypeData * child ) {
+	TypeData * type = new TypeData( TypeData::Qualified );
+	type->qualified.parent = parent;
+	type->qualified.child = child;
+	return type;
+}
+
+TypeData * build_typedef( const std::string * name ) {
+	TypeData * type = new TypeData( TypeData::SymbolicInst );
+	type->symbolic.name = name;
+	type->symbolic.isTypedef = true;
+	type->symbolic.actuals = nullptr;
+	return type;
+}
+
+TypeData * build_type_gen( const std::string * name, ExpressionNode * params ) {
+	TypeData * type = new TypeData( TypeData::SymbolicInst );
+	type->symbolic.name = name;
+	type->symbolic.isTypedef = false;
+	type->symbolic.actuals = params;
+	return type;
+}
+
+TypeData * build_vtable_type( TypeData * base ) {
+	TypeData * type = new TypeData( TypeData::Vtable );
+	type->base = base;
+	return type;
+}
+
+// Takes ownership of src.
+static void addQualifiersToType( TypeData * dst, TypeData * src ) {
+	if ( dst->base ) {
+		addQualifiersToType( dst->base, src );
+	} else if ( dst->kind == TypeData::Function ) {
+		dst->base = src;
+		src = nullptr;
+    } else {
+		dst->qualifiers |= src->qualifiers;
+		delete src;
+	} // if
+}
+
+// Takes ownership of all arguments, gives ownership of return value.
+TypeData * addQualifiers( TypeData * dst, TypeData * src ) {
+	if ( src->forall ) {
+		if ( dst->forall || TypeData::Aggregate != dst->kind ) {
+			extend( dst->forall, src->forall );
+		} else {
+			extend( dst->aggregate.params, src->forall );
+		}
+		src->forall = nullptr;
+	}
+
+	addQualifiersToType( dst, src );
+	return dst;
+}
+
+// Helper for addType and cloneBaseType.
+static void addTypeToType( TypeData *& dst, TypeData *& src ) {
+	if ( src->forall && dst->kind == TypeData::Function ) {
+		extend( dst->forall, src->forall );
+		src->forall = nullptr;
+	} // if
+	if ( dst->base ) {
+		addTypeToType( dst->base, src );
+		return;
+	}
+	switch ( dst->kind ) {
+	case TypeData::Unknown:
+		src->qualifiers |= dst->qualifiers;
+		// LEAKS dst?
+		dst = src;
+		src = nullptr;
+		break;
+	case TypeData::Basic:
+		dst->qualifiers |= src->qualifiers;
+		if ( src->kind != TypeData::Unknown ) {
+			assert( src->kind == TypeData::Basic );
+
+			if ( dst->basictype == TypeData::NoBasicType ) {
+				dst->basictype = src->basictype;
+			} else if ( src->basictype != TypeData::NoBasicType ) {
+				SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
+					TypeData::basicTypeNames[ dst->basictype ],
+					TypeData::basicTypeNames[ src->basictype ] );
+			}
+			if ( dst->complextype == TypeData::NoComplexType ) {
+				dst->complextype = src->complextype;
+			} else if ( src->complextype != TypeData::NoComplexType ) {
+				SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
+					TypeData::complexTypeNames[ src->complextype ],
+					TypeData::complexTypeNames[ src->complextype ] );
+			}
+			if ( dst->signedness == TypeData::NoSignedness ) {
+				dst->signedness = src->signedness;
+			} else if ( src->signedness != TypeData::NoSignedness ) {
+				SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
+					TypeData::signednessNames[ dst->signedness ],
+					TypeData::signednessNames[ src->signedness ] );
+			}
+			if ( dst->length == TypeData::NoLength ) {
+				dst->length = src->length;
+			} else if ( dst->length == TypeData::Long && src->length == TypeData::Long ) {
+				dst->length = TypeData::LongLong;
+			} else if ( src->length != TypeData::NoLength ) {
+				SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
+					TypeData::lengthNames[ dst->length ],
+					TypeData::lengthNames[ src->length ] );
+			}
+		} // if
+		break;
+	default:
+		if ( TypeData::Aggregate == src->kind ) {
+			dst->base = makeInstance( src );
+		} else {
+			extend( dst->forall, src->forall );
+			src->forall = nullptr;
+			dst->base = src;
+		}
+		src = nullptr;
+	} // switch
+}
+
+// Takes ownership of all arguments, gives ownership of return value.
+TypeData * addType( TypeData * dst, TypeData * src, std::vector<ast::ptr<ast::Attribute>> & attributes ) {
+	if ( dst ) {
+		addTypeToType( dst, src );
+	} else if ( src->kind == TypeData::Aggregate ) {
+		// Hide type information aggregate instances.
+		dst = makeInstance( src );
+		dst->aggInst.aggregate->aggregate.attributes.swap( attributes );
+	} else {
+		dst = src;
+	} // if
+	return dst;
+}
+
+TypeData * addType( TypeData * dst, TypeData * src ) {
+	std::vector<ast::ptr<ast::Attribute>> attributes;
+	return addType( dst, src, attributes );
+}
+
+// Takes ownership of both arguments, gives ownership of return value.
+TypeData * cloneBaseType( TypeData * type, TypeData * other ) {
+	TypeData * newType = type->getLastBase()->clone();
+	if ( newType->kind == TypeData::AggregateInst ) {
+		// don't duplicate members
+		assert( newType->aggInst.aggregate->kind == TypeData::Aggregate );
+		delete newType->aggInst.aggregate->aggregate.fields;
+		newType->aggInst.aggregate->aggregate.fields = nullptr;
+		newType->aggInst.aggregate->aggregate.body = false;
+		// don't hoist twice
+		newType->aggInst.hoistType = false;
+	} // if
+	newType->forall = maybeCopy( type->forall );
+
+	if ( other ) {
+		addTypeToType( other, newType );
+		delete newType;
+		return other;
+	} // if
+	return newType;
+}
+
+TypeData * makeNewBase( TypeData * type ) {
+	return ( TypeData::Aggregate == type->kind ) ? makeInstance( type ) : type;
+}
+
+
+void buildForall(
+		const DeclarationNode * firstNode,
+		std::vector<ast::ptr<ast::TypeInstType>> &outputList ) {
+	{
+		std::vector<ast::ptr<ast::Type>> tmpList;
+		buildTypeList( firstNode, tmpList );
+		for ( auto tmp : tmpList ) {
+			outputList.emplace_back(
+				strict_dynamic_cast<const ast::TypeInstType *>(
+					tmp.release() ) );
+		}
+	}
+	auto n = firstNode;
+	for ( auto i = outputList.begin() ;
+			i != outputList.end() ;
+			++i, n = n->next ) {
+		// Only the object type class adds additional assertions.
+		if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
+			continue;
+		}
+
+		ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>();
+		std::vector<ast::ptr<ast::DeclWithType>> newAssertions;
+		auto mutTypeDecl = ast::mutate( td );
+		const CodeLocation & location = mutTypeDecl->location;
+		*i = mutTypeDecl;
+
+		// add assertion parameters to `type' tyvars in reverse order
+		// add assignment operator:  T * ?=?(T *, T)
+		newAssertions.push_back( new ast::FunctionDecl(
+			location,
+			"?=?",
+			{}, // forall
+			{}, // assertions
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::ReferenceType( i->get() ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+				new ast::ObjectDecl(
+					location,
+					"",
+					i->get(),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // params
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					i->get(),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // returns
+			(ast::CompoundStmt *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+
+		// add default ctor:  void ?{}(T *)
+		newAssertions.push_back( new ast::FunctionDecl(
+			location,
+			"?{}",
+			{}, // forall
+			{}, // assertions
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::ReferenceType( i->get() ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // params
+			{}, // returns
+			(ast::CompoundStmt *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+
+		// add copy ctor:  void ?{}(T *, T)
+		newAssertions.push_back( new ast::FunctionDecl(
+			location,
+			"?{}",
+			{}, // forall
+			{}, // assertions
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::ReferenceType( i->get() ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+				new ast::ObjectDecl(
+					location,
+					"",
+					i->get(),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // params
+			{}, // returns
+			(ast::CompoundStmt *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+
+		// add dtor:  void ^?{}(T *)
+		newAssertions.push_back( new ast::FunctionDecl(
+			location,
+			"^?{}",
+			{}, // forall
+			{}, // assertions
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::ReferenceType( i->get() ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // params
+			{}, // returns
+			(ast::CompoundStmt *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+
+		spliceBegin( mutTypeDecl->assertions, newAssertions );
+	} // for
+}
+
+
+void buildForall(
+		const DeclarationNode * firstNode,
+		std::vector<ast::ptr<ast::TypeDecl>> &outputForall ) {
+	buildList( firstNode, outputForall );
+	auto n = firstNode;
+	for ( auto i = outputForall.begin() ;
+			i != outputForall.end() ;
+			++i, n = n->next ) {
+		// Only the object type class adds additional assertions.
+		if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
+			continue;
+		}
+
+		ast::TypeDecl const * td = i->strict_as<ast::TypeDecl>();
+		std::vector<ast::ptr<ast::DeclWithType>> newAssertions;
+		auto mutTypeDecl = ast::mutate( td );
+		const CodeLocation & location = mutTypeDecl->location;
+		*i = mutTypeDecl;
+
+		// add assertion parameters to `type' tyvars in reverse order
+		// add assignment operator:  T * ?=?(T *, T)
+		newAssertions.push_back( new ast::FunctionDecl(
+			location,
+			"?=?",
+			{}, // forall
+			{}, // assertions
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::ReferenceType( new ast::TypeInstType( td->name, *i ) ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::TypeInstType( td->name, *i ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // params
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::TypeInstType( td->name, *i ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // returns
+			(ast::CompoundStmt *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+
+		// add default ctor:  void ?{}(T *)
+		newAssertions.push_back( new ast::FunctionDecl(
+			location,
+			"?{}",
+			{}, // forall
+			{}, // assertions
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::ReferenceType(
+						new ast::TypeInstType( td->name, i->get() ) ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // params
+			{}, // returns
+			(ast::CompoundStmt *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+
+		// add copy ctor:  void ?{}(T *, T)
+		newAssertions.push_back( new ast::FunctionDecl(
+			location,
+			"?{}",
+			{}, // forall
+			{}, // assertions
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::ReferenceType(
+						new ast::TypeInstType( td->name, *i ) ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::TypeInstType( td->name, *i ),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // params
+			{}, // returns
+			(ast::CompoundStmt *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+
+		// add dtor:  void ^?{}(T *)
+		newAssertions.push_back( new ast::FunctionDecl(
+			location,
+			"^?{}",
+			{}, // forall
+			{}, // assertions
+			{
+				new ast::ObjectDecl(
+					location,
+					"",
+					new ast::ReferenceType(
+						new ast::TypeInstType( i->get() )
+					),
+					(ast::Init *)nullptr,
+					ast::Storage::Classes(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr
+				),
+			}, // params
+			{}, // returns
+			(ast::CompoundStmt *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+
+		spliceBegin( mutTypeDecl->assertions, newAssertions );
+	} // for
+} // buildForall
+
+
+ast::Type * typebuild( const TypeData * td ) {
+	assert( td );
+	switch ( td->kind ) {
+	case TypeData::Unknown:
+		// fill in implicit int
+		return new ast::BasicType(
+			ast::BasicKind::SignedInt,
+			buildQualifiers( td )
+		);
+	case TypeData::Basic:
+		return buildBasicType( td );
+	case TypeData::Pointer:
+		return buildPointer( td );
+	case TypeData::Array:
+		return buildArray( td );
+	case TypeData::Reference:
+		return buildReference( td );
+	case TypeData::Function:
+		return buildFunctionType( td );
+	case TypeData::AggregateInst:
+		return buildAggInst( td );
+	case TypeData::EnumConstant:
+		return new ast::EnumInstType( "", buildQualifiers( td ) );
+	case TypeData::SymbolicInst:
+		return buildSymbolicInst( td );
+	case TypeData::Tuple:
+		return buildTuple( td );
+	case TypeData::Typeof:
+	case TypeData::Basetypeof:
+		return buildTypeof( td );
+	case TypeData::Vtable:
+		return buildVtable( td );
+	case TypeData::Builtin:
+		switch ( td->builtintype ) {
+		case TypeData::Zero:
+			return new ast::ZeroType();
+		case TypeData::One:
+			return new ast::OneType();
+		default:
+			return new ast::VarArgsType( buildQualifiers( td ) );
+		} // switch
+	case TypeData::GlobalScope:
+		return new ast::GlobalScopeType();
+	case TypeData::Qualified:
+		return new ast::QualifiedType(
+			typebuild( td->qualified.parent ),
+			typebuild( td->qualified.child ),
+			buildQualifiers( td )
+		);
+	case TypeData::Symbolic:
+	case TypeData::Aggregate:
+		assert( false );
+	} // switch
+
+	return nullptr;
+} // typebuild
+
+
+TypeData * typeextractAggregate( const TypeData * td, bool toplevel ) {
+	TypeData * ret = nullptr;
+
+	switch ( td->kind ) {
+	case TypeData::Aggregate:
+		if ( ! toplevel && td->aggregate.body ) {
+			ret = td->clone();
+		} // if
+		break;
+	case TypeData::AggregateInst:
+		if ( td->aggInst.aggregate ) {
+			ret = typeextractAggregate( td->aggInst.aggregate, false );
+		} // if
+		break;
+	default:
+		if ( td->base ) {
+			ret = typeextractAggregate( td->base, false );
+		} // if
+	} // switch
+	return ret;
+} // typeextractAggregate
+
+
+ast::CV::Qualifiers buildQualifiers( const TypeData * td ) {
+	return td->qualifiers;
+} // buildQualifiers
+
+
+static string genTSError( string msg, TypeData::BasicType basictype ) {
+	SemanticError( yylloc, "invalid type specifier \"%s\" for type \"%s\".", msg.c_str(), TypeData::basicTypeNames[basictype] );
+} // genTSError
+
+ast::Type * buildBasicType( const TypeData * td ) {
+	ast::BasicKind ret;
+
+	switch ( td->basictype ) {
+	case TypeData::Void:
+		if ( td->signedness != TypeData::NoSignedness ) {
+			genTSError( TypeData::signednessNames[ td->signedness ], td->basictype );
+		} // if
+		if ( td->length != TypeData::NoLength ) {
+			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
+		} // if
+		return new ast::VoidType( buildQualifiers( td ) );
+		break;
+
+	case TypeData::Bool:
+		if ( td->signedness != TypeData::NoSignedness ) {
+			genTSError( TypeData::signednessNames[ td->signedness ], td->basictype );
+		} // if
+		if ( td->length != TypeData::NoLength ) {
+			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
+		} // if
+
+		ret = ast::BasicKind::Bool;
+		break;
+
+	case TypeData::Char:
+		// C11 Standard 6.2.5.15: The three types char, signed char, and unsigned char are collectively called the
+		// character types. The implementation shall define char to have the same range, representation, and behavior as
+		// either signed char or unsigned char.
+		static ast::BasicKind chartype[] = { ast::BasicKind::SignedChar, ast::BasicKind::UnsignedChar, ast::BasicKind::Char };
+
+		if ( td->length != TypeData::NoLength ) {
+			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
+		} // if
+
+		ret = chartype[ td->signedness ];
+		break;
+
+	case TypeData::Int:
+		static ast::BasicKind inttype[2][4] = {
+			{ ast::BasicKind::ShortSignedInt, ast::BasicKind::LongSignedInt, ast::BasicKind::LongLongSignedInt, ast::BasicKind::SignedInt },
+			{ ast::BasicKind::ShortUnsignedInt, ast::BasicKind::LongUnsignedInt, ast::BasicKind::LongLongUnsignedInt, ast::BasicKind::UnsignedInt },
+		};
+
+	Integral: ;
+		if ( td->signedness == TypeData::NoSignedness ) {
+			const_cast<TypeData *>(td)->signedness = TypeData::Signed;
+		} // if
+		ret = inttype[ td->signedness ][ td->length ];
+		break;
+
+	case TypeData::Int128:
+		ret = td->signedness == TypeData::Unsigned ? ast::BasicKind::UnsignedInt128 : ast::BasicKind::SignedInt128;
+		if ( td->length != TypeData::NoLength ) {
+			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
+		} // if
+		break;
+
+	case TypeData::Float:
+	case TypeData::Double:
+	case TypeData::LongDouble:					// not set until below
+	case TypeData::uuFloat80:
+	case TypeData::uuFloat128:
+	case TypeData::uFloat16:
+	case TypeData::uFloat32:
+	case TypeData::uFloat32x:
+	case TypeData::uFloat64:
+	case TypeData::uFloat64x:
+	case TypeData::uFloat128:
+	case TypeData::uFloat128x:
+		static ast::BasicKind floattype[2][12] = {
+			{ ast::BasicKind::FloatComplex, ast::BasicKind::DoubleComplex, ast::BasicKind::LongDoubleComplex, (ast::BasicKind)-1, (ast::BasicKind)-1, ast::BasicKind::uFloat16Complex, ast::BasicKind::uFloat32Complex, ast::BasicKind::uFloat32xComplex, ast::BasicKind::uFloat64Complex, ast::BasicKind::uFloat64xComplex, ast::BasicKind::uFloat128Complex, ast::BasicKind::uFloat128xComplex, },
+			{ ast::BasicKind::Float, ast::BasicKind::Double, ast::BasicKind::LongDouble, ast::BasicKind::uuFloat80, ast::BasicKind::uuFloat128, ast::BasicKind::uFloat16, ast::BasicKind::uFloat32, ast::BasicKind::uFloat32x, ast::BasicKind::uFloat64, ast::BasicKind::uFloat64x, ast::BasicKind::uFloat128, ast::BasicKind::uFloat128x, },
+		};
+
+	FloatingPoint: ;
+		if ( td->signedness != TypeData::NoSignedness ) {
+			genTSError( TypeData::signednessNames[ td->signedness ], td->basictype );
+		} // if
+		if ( td->length == TypeData::Short || td->length == TypeData::LongLong ) {
+			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
+		} // if
+		if ( td->basictype != TypeData::Double && td->length == TypeData::Long ) {
+			genTSError( TypeData::lengthNames[ td->length ], td->basictype );
+		} // if
+		if ( td->complextype == TypeData::Imaginary ) {
+			genTSError( TypeData::complexTypeNames[ td->complextype ], td->basictype );
+		} // if
+		if ( (td->basictype == TypeData::uuFloat80 || td->basictype == TypeData::uuFloat128) && td->complextype == TypeData::Complex ) { // gcc unsupported
+			genTSError( TypeData::complexTypeNames[ td->complextype ], td->basictype );
+		} // if
+		if ( td->length == TypeData::Long ) {
+			const_cast<TypeData *>(td)->basictype = TypeData::LongDouble;
+		} // if
+
+		ret = floattype[ td->complextype ][ td->basictype - TypeData::Float ];
+		//printf( "XXXX %d %d %d %d\n", td->complextype, td->basictype, TypeData::Float, ret );
+		break;
+
+	case TypeData::NoBasicType:
+		// No basic type in declaration => default double for Complex/Imaginary and int type for integral types
+		if ( td->complextype == TypeData::Complex || td->complextype == TypeData::Imaginary ) {
+			const_cast<TypeData *>(td)->basictype = TypeData::Double;
+			goto FloatingPoint;
+		} // if
+
+		const_cast<TypeData *>(td)->basictype = TypeData::Int;
+		goto Integral;
+	default:
+		assertf( false, "unknown basic type" );
+		return nullptr;
+	} // switch
+
+	ast::BasicType * bt = new ast::BasicType( ret, buildQualifiers( td ) );
+	return bt;
+} // buildBasicType
+
+
+static ast::Type * buildDefaultType( const TypeData * td ) {
+	return ( td ) ? typebuild( td ) : new ast::BasicType( ast::BasicKind::SignedInt );
+} // buildDefaultType
+
+
+ast::PointerType * buildPointer( const TypeData * td ) {
+	return new ast::PointerType(
+		buildDefaultType( td->base ),
+		buildQualifiers( td )
+	);
+} // buildPointer
+
+
+ast::ArrayType * buildArray( const TypeData * td ) {
+	return new ast::ArrayType(
+		buildDefaultType( td->base ),
+		maybeBuild( td->array.dimension ),
+		td->array.isVarLen ? ast::VariableLen : ast::FixedLen,
+		td->array.isStatic ? ast::StaticDim : ast::DynamicDim,
+		buildQualifiers( td )
+	);
+} // buildArray
+
+
+ast::ReferenceType * buildReference( const TypeData * td ) {
+	return new ast::ReferenceType(
+		buildDefaultType( td->base ),
+		buildQualifiers( td )
+	);
+} // buildReference
+
+
+ast::AggregateDecl * buildAggregate( const TypeData * td, std::vector<ast::ptr<ast::Attribute>> attributes, ast::Linkage::Spec linkage ) {
+	assert( td->kind == TypeData::Aggregate );
+	ast::AggregateDecl * at;
+	switch ( td->aggregate.kind ) {
+	case ast::AggregateDecl::Struct:
+	case ast::AggregateDecl::Coroutine:
+	case ast::AggregateDecl::Exception:
+	case ast::AggregateDecl::Generator:
+	case ast::AggregateDecl::Monitor:
+	case ast::AggregateDecl::Thread:
+		at = new ast::StructDecl( td->location,
+			*td->aggregate.name,
+			td->aggregate.kind,
+			std::move( attributes ),
+			linkage
+		);
+		buildForall( td->aggregate.params, at->params );
+		break;
+	case ast::AggregateDecl::Union:
+		at = new ast::UnionDecl( td->location,
+			*td->aggregate.name,
+			std::move( attributes ),
+			linkage
+		);
+		buildForall( td->aggregate.params, at->params );
+		break;
+	case ast::AggregateDecl::Enum:
+		return buildEnum( td, std::move( attributes ), linkage );
+	case ast::AggregateDecl::Trait:
+		at = new ast::TraitDecl( td->location,
+			*td->aggregate.name,
+			std::move( attributes ),
+			linkage
+		);
+		buildList( td->aggregate.params, at->params );
+		break;
+	default:
+		assert( false );
+	} // switch
+
+	buildList( td->aggregate.fields, at->members );
+	at->set_body( td->aggregate.body );
+
+	return at;
+} // buildAggregate
+
+
+ast::BaseInstType * buildComAggInst(
+		const TypeData * td,
+		std::vector<ast::ptr<ast::Attribute>> && attributes,
+		ast::Linkage::Spec linkage ) {
+	switch ( td->kind ) {
+	case TypeData::Aggregate:
+		if ( td->aggregate.body ) {
+			ast::AggregateDecl * typedecl =
+				buildAggregate( td, std::move( attributes ), linkage );
+			switch ( td->aggregate.kind ) {
+			case ast::AggregateDecl::Struct:
+			case ast::AggregateDecl::Coroutine:
+			case ast::AggregateDecl::Monitor:
+			case ast::AggregateDecl::Thread:
+				return new ast::StructInstType(
+					strict_dynamic_cast<ast::StructDecl *>( typedecl ),
+					buildQualifiers( td )
+				);
+			case ast::AggregateDecl::Union:
+				return new ast::UnionInstType(
+					strict_dynamic_cast<ast::UnionDecl *>( typedecl ),
+					buildQualifiers( td )
+				);
+			case ast::AggregateDecl::Enum:
+				return new ast::EnumInstType(
+					strict_dynamic_cast<ast::EnumDecl *>( typedecl ),
+					buildQualifiers( td )
+				);
+			case ast::AggregateDecl::Trait:
+				assert( false );
+				break;
+			default:
+				assert( false );
+			} // switch
+		} else {
+			switch ( td->aggregate.kind ) {
+			case ast::AggregateDecl::Struct:
+			case ast::AggregateDecl::Coroutine:
+			case ast::AggregateDecl::Monitor:
+			case ast::AggregateDecl::Thread:
+				return new ast::StructInstType(
+					*td->aggregate.name,
+					buildQualifiers( td )
+				);
+			case ast::AggregateDecl::Union:
+				return new ast::UnionInstType(
+					*td->aggregate.name,
+					buildQualifiers( td )
+				);
+			case ast::AggregateDecl::Enum:
+				return new ast::EnumInstType(
+					*td->aggregate.name,
+					buildQualifiers( td )
+				);
+			case ast::AggregateDecl::Trait:
+				return new ast::TraitInstType(
+					*td->aggregate.name,
+					buildQualifiers( td )
+				);
+			default:
+				assert( false );
+			} // switch
+			break;
+		} // if
+		break;
+	default:
+		assert( false );
+	} // switch
+	assert( false );
+} // buildAggInst
+
+
+ast::BaseInstType * buildAggInst( const TypeData * td ) {
+	assert( td->kind == TypeData::AggregateInst );
+
+	ast::BaseInstType * ret = nullptr;
+	TypeData * type = td->aggInst.aggregate;
+	switch ( type->kind ) {
+	case TypeData::Aggregate:
+		switch ( type->aggregate.kind ) {
+		case ast::AggregateDecl::Struct:
+		case ast::AggregateDecl::Coroutine:
+		case ast::AggregateDecl::Monitor:
+		case ast::AggregateDecl::Thread:
+			ret = new ast::StructInstType(
+				*type->aggregate.name,
+				buildQualifiers( type )
+			);
+			break;
+		case ast::AggregateDecl::Union:
+			ret = new ast::UnionInstType(
+				*type->aggregate.name,
+				buildQualifiers( type )
+			);
+			break;
+		case ast::AggregateDecl::Enum:
+			ret = new ast::EnumInstType(
+				*type->aggregate.name,
+				buildQualifiers( type )
+			);
+			break;
+		case ast::AggregateDecl::Trait:
+			ret = new ast::TraitInstType(
+				*type->aggregate.name,
+				buildQualifiers( type )
+			);
+			break;
+		default:
+			assert( false );
+		} // switch
+		break;
+	default:
+		assert( false );
+	} // switch
+
+	ret->hoistType = td->aggInst.hoistType;
+	buildList( td->aggInst.params, ret->params );
+	return ret;
+} // buildAggInst
+
+
+ast::NamedTypeDecl * buildSymbolic(
+		const TypeData * td,
+		std::vector<ast::ptr<ast::Attribute>> attributes,
+		const std::string & name,
+		ast::Storage::Classes scs,
+		ast::Linkage::Spec linkage ) {
+	assert( td->kind == TypeData::Symbolic );
+	ast::NamedTypeDecl * ret;
+	assert( td->base );
+	if ( td->symbolic.isTypedef ) {
+		ret = new ast::TypedefDecl(
+			td->location,
+			name,
+			scs,
+			typebuild( td->base ),
+			linkage
+		);
+	} else {
+		ret = new ast::TypeDecl(
+			td->location,
+			name,
+			scs,
+			typebuild( td->base ),
+			ast::TypeDecl::Dtype,
+			true
+		);
+	} // if
+	buildList( td->symbolic.assertions, ret->assertions );
+	splice( ret->base.get_and_mutate()->attributes, attributes );
+	return ret;
+} // buildSymbolic
+
+
+ast::EnumDecl * buildEnum(
+		const TypeData * td,
+		std::vector<ast::ptr<ast::Attribute>> && attributes,
+		ast::Linkage::Spec linkage ) {
+	assert( td->kind == TypeData::Aggregate );
+	assert( td->aggregate.kind == ast::AggregateDecl::Enum );
+	ast::Type * baseType = td->base ? typebuild(td->base) : nullptr;
+	ast::EnumDecl * ret = new ast::EnumDecl(
+		td->location,
+		*td->aggregate.name,
+		td->aggregate.typed,
+		std::move( attributes ),
+		linkage,
+		baseType
+	);
+	buildList( td->aggregate.fields, ret->members );
+	auto members = ret->members.begin();
+	ret->hide = td->aggregate.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
+	for ( const DeclarationNode * cur = td->aggregate.fields ; cur != nullptr ; cur = cur->next, ++members ) {
+		if ( cur->enumInLine ) {
+			// Do Nothing
+		} else if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
+			SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
+		} else if ( cur->has_enumeratorValue() ) {
+			ast::Decl * member = members->get_and_mutate();
+			ast::ObjectDecl * object = strict_dynamic_cast<ast::ObjectDecl *>( member );
+			object->init = new ast::SingleInit(
+				td->location,
+				maybeMoveBuild( cur->consume_enumeratorValue() ),
+				ast::NoConstruct
+			);
+		} else if ( !cur->initializer ) {
+			if ( baseType && (!dynamic_cast<ast::BasicType *>(baseType) || !dynamic_cast<ast::BasicType *>(baseType)->isInteger())) {
+				SemanticError( td->location, "Enumerators of an non-integer typed enum must be explicitly initialized." );
+			}
+		}
+		// else cur is a List Initializer and has been set as init in buildList()
+		// if
+	} // for
+	ret->body = td->aggregate.body;
+	return ret;
+} // buildEnum
+
+
+ast::TypeInstType * buildSymbolicInst( const TypeData * td ) {
+	assert( td->kind == TypeData::SymbolicInst );
+	ast::TypeInstType * ret = new ast::TypeInstType(
+		*td->symbolic.name,
+		ast::TypeDecl::Dtype,
+		buildQualifiers( td )
+	);
+	buildList( td->symbolic.actuals, ret->params );
+	return ret;
+} // buildSymbolicInst
+
+
+ast::TupleType * buildTuple( const TypeData * td ) {
+	assert( td->kind == TypeData::Tuple );
+	std::vector<ast::ptr<ast::Type>> types;
+	buildTypeList( td->tuple, types );
+	ast::TupleType * ret = new ast::TupleType(
+		std::move( types ),
+		buildQualifiers( td )
+	);
+	return ret;
+} // buildTuple
+
+
+ast::TypeofType * buildTypeof( const TypeData * td ) {
+	assert( td->kind == TypeData::Typeof || td->kind == TypeData::Basetypeof );
+	assert( td->typeexpr );
+	return new ast::TypeofType(
+		td->typeexpr->build(),
+		td->kind == TypeData::Typeof
+			? ast::TypeofType::Typeof : ast::TypeofType::Basetypeof,
+		buildQualifiers( td )
+	);
+} // buildTypeof
+
+
+ast::VTableType * buildVtable( const TypeData * td ) {
+	assert( td->base );
+	return new ast::VTableType(
+		typebuild( td->base ),
+		buildQualifiers( td )
+	);
+} // buildVtable
+
+
+ast::FunctionDecl * buildFunctionDecl(
+		const TypeData * td,
+		const string &name,
+		ast::Storage::Classes scs,
+		ast::Function::Specs funcSpec,
+		ast::Linkage::Spec linkage,
+		ast::Expr * asmName,
+		std::vector<ast::ptr<ast::Attribute>> && attributes ) {
+	assert( td->kind == TypeData::Function );
+	// For some reason FunctionDecl takes a bool instead of an ArgumentFlag.
+	bool isVarArgs = !td->function.params || td->function.params->hasEllipsis;
+	ast::CV::Qualifiers cvq = buildQualifiers( td );
+	std::vector<ast::ptr<ast::TypeDecl>> forall;
+	std::vector<ast::ptr<ast::DeclWithType>> assertions;
+	std::vector<ast::ptr<ast::DeclWithType>> params;
+	std::vector<ast::ptr<ast::DeclWithType>> returns;
+	buildList( td->function.params, params );
+	buildForall( td->forall, forall );
+	// Functions do not store their assertions there anymore.
+	for ( ast::ptr<ast::TypeDecl> & type_param : forall ) {
+		auto mut = type_param.get_and_mutate();
+		splice( assertions, mut->assertions );
+	}
+	if ( td->base ) {
+		switch ( td->base->kind ) {
+		case TypeData::Tuple:
+			buildList( td->base->tuple, returns );
+			break;
+		default:
+			returns.push_back( dynamic_cast<ast::DeclWithType *>(
+				buildDecl(
+					td->base,
+					"",
+					ast::Storage::Classes(),
+					(ast::Expr *)nullptr, // bitfieldWidth
+					ast::Function::Specs(),
+					ast::Linkage::Cforall,
+					(ast::Expr *)nullptr // asmName
+				)
+			) );
+		} // switch
+	} else {
+		returns.push_back( new ast::ObjectDecl(
+			td->location,
+			"",
+			new ast::BasicType( ast::BasicKind::SignedInt ),
+			(ast::Init *)nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		) );
+	} // if
+	ast::Stmt * stmt = maybeBuild( td->function.body );
+	ast::CompoundStmt * body = dynamic_cast<ast::CompoundStmt *>( stmt );
+	ast::FunctionDecl * decl = new ast::FunctionDecl( td->location,
+		name,
+		std::move( forall ),
+		std::move( assertions ),
+		std::move( params ),
+		std::move( returns ),
+		body,
+		scs,
+		linkage,
+		std::move( attributes ),
+		funcSpec,
+		(isVarArgs) ? ast::VariableArgs : ast::FixedArgs
+	);
+	buildList( td->function.withExprs, decl->withExprs );
+	decl->asmName = asmName;
+	// This may be redundant on a declaration.
+	decl->type.get_and_mutate()->qualifiers = cvq;
+	return decl;
+} // buildFunctionDecl
+
+
+ast::Decl * buildDecl(
+		const TypeData * td,
+		const string &name,
+		ast::Storage::Classes scs,
+		ast::Expr * bitfieldWidth,
+		ast::Function::Specs funcSpec,
+		ast::Linkage::Spec linkage,
+		ast::Expr * asmName,
+		ast::Init * init,
+		std::vector<ast::ptr<ast::Attribute>> && attributes ) {
+	if ( td->kind == TypeData::Function ) {
+		if ( td->function.idList ) {					// KR function ?
+			buildKRFunction( td->function );			// transform into C11 function
+		} // if
+
+		return buildFunctionDecl(
+			td, name, scs, funcSpec, linkage,
+			asmName, std::move( attributes ) );
+	} else if ( td->kind == TypeData::Aggregate ) {
+		return buildAggregate( td, std::move( attributes ), linkage );
+	} else if ( td->kind == TypeData::Symbolic ) {
+		return buildSymbolic( td, std::move( attributes ), name, scs, linkage );
+	} else {
+		auto ret = new ast::ObjectDecl( td->location,
+			name,
+			typebuild( td ),
+			init,
+			scs,
+			linkage,
+			bitfieldWidth,
+			std::move( attributes )
+		);
+		ret->asmName = asmName;
+		return ret;
+	} // if
+	return nullptr;
+} // buildDecl
+
+
+ast::FunctionType * buildFunctionType( const TypeData * td ) {
+	assert( td->kind == TypeData::Function );
+	ast::FunctionType * ft = new ast::FunctionType(
+		( !td->function.params || td->function.params->hasEllipsis )
+			? ast::VariableArgs : ast::FixedArgs,
+		buildQualifiers( td )
+	);
+	buildTypeList( td->function.params, ft->params );
+	buildForall( td->forall, ft->forall );
+	if ( td->base ) {
+		switch ( td->base->kind ) {
+		case TypeData::Tuple:
+			buildTypeList( td->base->tuple, ft->returns );
+			break;
+		default:
+			ft->returns.push_back( typebuild( td->base ) );
+			break;
+		} // switch
+	} else {
+		ft->returns.push_back(
+			new ast::BasicType( ast::BasicKind::SignedInt ) );
+	} // if
+	return ft;
+} // buildFunctionType
+
+
+// Transform KR routine declarations into C99 routine declarations:
+//
+//    rtn( a, b, c ) int a, c; double b {}  =>  int rtn( int a, double c, int b ) {}
+//
+// The type information for each post-declaration is moved to the corresponding pre-parameter and the post-declaration
+// is deleted. Note, the order of the parameter names may not be the same as the declaration names. Duplicate names and
+// extra names are disallowed.
+//
+// Note, there is no KR routine-prototype syntax:
+//
+//    rtn( a, b, c ) int a, c; double b; // invalid KR prototype
+//    rtn(); // valid KR prototype
+
+void buildKRFunction( const TypeData::Function_t & function ) {
+	assert( ! function.params );
+	// loop over declaration first as it is easier to spot errors
+	for ( DeclarationNode * decl = function.oldDeclList; decl != nullptr; decl = decl->next ) {
+		// scan ALL parameter names for each declaration name to check for duplicates
+		for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
+			if ( *decl->name == *param->name ) {
+				// type set => parameter name already transformed by a declaration names so there is a duplicate
+				// declaration name attempting a second transformation
+				if ( param->type ) SemanticError( param->location, "duplicate declaration name \"%s\".", param->name->c_str() );
+				// declaration type reset => declaration already transformed by a parameter name so there is a duplicate
+				// parameter name attempting a second transformation
+				if ( ! decl->type ) SemanticError( param->location, "duplicate parameter name \"%s\".", param->name->c_str() );
+				param->type = decl->type;				// set copy declaration type to parameter type
+				decl->type = nullptr;					// reset declaration type
+				// Copy and reset attributes from declaration to parameter:
+				splice( param->attributes, decl->attributes );
+			} // if
+		} // for
+		// declaration type still set => type not moved to a matching parameter so there is a missing parameter name
+		if ( decl->type ) SemanticError( decl->location, "missing name in parameter list %s", decl->name->c_str() );
+	} // for
+
+	// Parameter names without a declaration default to type int:
+	//
+	//    rtb( a, b, c ) const char * b; {} => int rtn( int a, const char * b, int c ) {}
+
+	for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
+		if ( ! param->type ) {							// generate type int for empty parameter type
+			param->type = new TypeData( TypeData::Basic );
+			param->type->basictype = TypeData::Int;
+		} // if
+	} // for
+
+	function.params = function.idList;					// newly modified idList becomes parameters
+	function.idList = nullptr;							// idList now empty
+	delete function.oldDeclList;						// deletes entire list
+	function.oldDeclList = nullptr;						// reset
+} // buildKRFunction
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,187 +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.
-//
-// TypeData.h --
-//
-// Author           : Peter A. Buhr
-// Created On       : Sat May 16 15:18:36 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Feb 22 16:30:31 2024
-// Update Count     : 210
-//
-
-#pragma once
-
-#include <iosfwd>                                   // for ostream
-#include <list>                                     // for list
-#include <string>                                   // for string
-
-#include "AST/CVQualifiers.hpp"                     // for CV
-#include "AST/Fwd.hpp"                              // for Type
-#include "DeclarationNode.h"                        // for DeclarationNode
-
-struct TypeData {
-	// Type flags used in this type, and there names (harmonize with implementation).
-	enum BasicType {
-		Void, Bool, Char, Int, Int128,
-		Float, Double, LongDouble, uuFloat80, uuFloat128,
-		uFloat16, uFloat32, uFloat32x, uFloat64, uFloat64x, uFloat128, uFloat128x,
-		NoBasicType
-	};
-	static const char * basicTypeNames[];
-	enum ComplexType { Complex, NoComplexType, Imaginary };
-	// Imaginary unsupported => parse, but make invisible and print error message
-	static const char * complexTypeNames[];
-	enum Signedness { Signed, Unsigned, NoSignedness };
-	static const char * signednessNames[];
-	enum Length { Short, Long, LongLong, NoLength };
-	static const char * lengthNames[];
-	enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType };
-	static const char * builtinTypeNames[];
-
-	enum Kind { Basic, Pointer, Reference, Array, Function, Aggregate, AggregateInst, EnumConstant, Symbolic,
-				SymbolicInst, Tuple, Basetypeof, Typeof, Vtable, Builtin, GlobalScope, Qualified, Unknown };
-
-	struct Aggregate_t {
-		ast::AggregateDecl::Aggregate kind;
-		const std::string * name = nullptr;
-		// Polymorphics parameters. (Polymorphic types only.)
-		DeclarationNode * params = nullptr;
-		// Arguments later applied to AggInst. (Polymorphic types only.)
-		ExpressionNode * actuals = nullptr;
-		// Only set if body is true. (Constants for enumerations.)
-		DeclarationNode * fields = nullptr;
-		std::vector<ast::ptr<ast::Attribute>> attributes;
-		// Is this a declaration with a body (may have fields)?
-		bool body;
-		// Is this type anonymous? (Name can still be set to generated name.)
-		bool anon;
-		// Is this a typed enumeration? Type may be stored in base.
-		bool typed;
-		EnumHiding hiding;
-	};
-
-	struct AggInst_t {
-		TypeData * aggregate = nullptr;
-		ExpressionNode * params = nullptr;
-		bool hoistType;
-	};
-
-	struct Array_t {
-		ExpressionNode * dimension = nullptr;
-		bool isVarLen;
-		bool isStatic;
-	};
-
-	struct Function_t {
-		mutable DeclarationNode * params = nullptr;		// mutables modified in buildKRFunction
-		mutable DeclarationNode * idList = nullptr;		// old-style
-		mutable DeclarationNode * oldDeclList = nullptr;
-		StatementNode * body = nullptr;
-		ExpressionNode * withExprs = nullptr;			// expressions from function's with_clause
-	};
-
-	struct Symbolic_t {
-		const std::string * name = nullptr;
-		bool isTypedef;									// false => TYPEGENname, true => TYPEDEFname
-		DeclarationNode * params = nullptr;
-		ExpressionNode * actuals = nullptr;
-		DeclarationNode * assertions = nullptr;
-	};
-
-	struct Qualified_t {								// qualified type S.T
-		TypeData * parent = nullptr;
-		TypeData * child = nullptr;
-	};
-
-	CodeLocation location;
-
-	Kind kind;
-	TypeData * base;
-	BasicType basictype = NoBasicType;
-	ComplexType complextype = NoComplexType;
-	Signedness signedness = NoSignedness;
-	Length length = NoLength;
-	BuiltinType builtintype = NoBuiltinType;
-
-	ast::CV::Qualifiers qualifiers;
-	DeclarationNode * forall = nullptr;
-
-	Aggregate_t aggregate;
-	AggInst_t aggInst;
-	Array_t array;
-	Function_t function;
-	Symbolic_t symbolic;
-	Qualified_t qualified;
-	DeclarationNode * tuple = nullptr;
-	ExpressionNode * typeexpr = nullptr;
-
-	TypeData( Kind k = Unknown );
-	~TypeData();
-	void print( std::ostream &, int indent = 0 ) const;
-	TypeData * clone() const;
-
-	const std::string * leafName() const;
-
-	TypeData * getLastBase();
-	void setLastBase( TypeData * );
-};
-
-
-TypeData * build_type_qualifier( ast::CV::Qualifiers );
-TypeData * build_basic_type( TypeData::BasicType );
-TypeData * build_complex_type( TypeData::ComplexType );
-TypeData * build_signedness( TypeData::Signedness );
-TypeData * build_builtin_type( TypeData::BuiltinType );
-TypeData * build_length( TypeData::Length );
-TypeData * build_forall( DeclarationNode * );
-TypeData * build_global_scope();
-TypeData * build_qualified_type( TypeData *, TypeData * );
-TypeData * build_typedef( const std::string * name );
-TypeData * build_type_gen( const std::string * name, ExpressionNode * params );
-TypeData * build_vtable_type( TypeData * );
-
-TypeData * addQualifiers( TypeData * ltype, TypeData * rtype );
-TypeData * addType( TypeData * ltype, TypeData * rtype, std::vector<ast::ptr<ast::Attribute>> & );
-TypeData * addType( TypeData * ltype, TypeData * rtype );
-TypeData * cloneBaseType( TypeData * type, TypeData * other );
-TypeData * makeNewBase( TypeData * type );
-
-
-ast::Type * typebuild( const TypeData * );
-TypeData * typeextractAggregate( const TypeData * td, bool toplevel = true );
-ast::CV::Qualifiers buildQualifiers( const TypeData * td );
-ast::Type * buildBasicType( const TypeData * );
-ast::PointerType * buildPointer( const TypeData * );
-ast::ArrayType * buildArray( const TypeData * );
-ast::ReferenceType * buildReference( const TypeData * );
-ast::AggregateDecl * buildAggregate( const TypeData *, std::vector<ast::ptr<ast::Attribute>> );
-ast::BaseInstType * buildComAggInst( const TypeData *, std::vector<ast::ptr<ast::Attribute>> && attributes, ast::Linkage::Spec linkage );
-ast::BaseInstType * buildAggInst( const TypeData * );
-ast::TypeDecl * buildVariable( const TypeData * );
-ast::EnumDecl * buildEnum( const TypeData *, std::vector<ast::ptr<ast::Attribute>> &&, ast::Linkage::Spec );
-ast::TypeInstType * buildSymbolicInst( const TypeData * );
-ast::TupleType * buildTuple( const TypeData * );
-ast::TypeofType * buildTypeof( const TypeData * );
-ast::VTableType * buildVtable( const TypeData * );
-ast::Decl * buildDecl(
-	const TypeData *, const std::string &, ast::Storage::Classes, ast::Expr *,
-	ast::Function::Specs funcSpec, ast::Linkage::Spec, ast::Expr * asmName,
-	ast::Init * init = nullptr, std::vector<ast::ptr<ast::Attribute>> && attributes = std::vector<ast::ptr<ast::Attribute>>() );
-ast::FunctionType * buildFunctionType( const TypeData * );
-void buildKRFunction( const TypeData::Function_t & function );
-
-static inline ast::Type * maybeMoveBuildType( TypeData * type ) {
-	ast::Type * ret = type ? typebuild( type ) : nullptr;
-	delete type;
-	return ret;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/TypeData.hpp
===================================================================
--- src/Parser/TypeData.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/TypeData.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,187 @@
+//
+// 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.
+//
+// TypeData.hpp --
+//
+// Author           : Peter A. Buhr
+// Created On       : Sat May 16 15:18:36 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Feb 22 16:30:31 2024
+// Update Count     : 210
+//
+
+#pragma once
+
+#include <iosfwd>                                   // for ostream
+#include <list>                                     // for list
+#include <string>                                   // for string
+
+#include "AST/CVQualifiers.hpp"                     // for CV
+#include "AST/Fwd.hpp"                              // for Type
+#include "DeclarationNode.hpp"                      // for DeclarationNode
+
+struct TypeData {
+	// Type flags used in this type, and there names (harmonize with implementation).
+	enum BasicType {
+		Void, Bool, Char, Int, Int128,
+		Float, Double, LongDouble, uuFloat80, uuFloat128,
+		uFloat16, uFloat32, uFloat32x, uFloat64, uFloat64x, uFloat128, uFloat128x,
+		NoBasicType
+	};
+	static const char * basicTypeNames[];
+	enum ComplexType { Complex, NoComplexType, Imaginary };
+	// Imaginary unsupported => parse, but make invisible and print error message
+	static const char * complexTypeNames[];
+	enum Signedness { Signed, Unsigned, NoSignedness };
+	static const char * signednessNames[];
+	enum Length { Short, Long, LongLong, NoLength };
+	static const char * lengthNames[];
+	enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType };
+	static const char * builtinTypeNames[];
+
+	enum Kind { Basic, Pointer, Reference, Array, Function, Aggregate, AggregateInst, EnumConstant, Symbolic,
+				SymbolicInst, Tuple, Basetypeof, Typeof, Vtable, Builtin, GlobalScope, Qualified, Unknown };
+
+	struct Aggregate_t {
+		ast::AggregateDecl::Aggregate kind;
+		const std::string * name = nullptr;
+		// Polymorphics parameters. (Polymorphic types only.)
+		DeclarationNode * params = nullptr;
+		// Arguments later applied to AggInst. (Polymorphic types only.)
+		ExpressionNode * actuals = nullptr;
+		// Only set if body is true. (Constants for enumerations.)
+		DeclarationNode * fields = nullptr;
+		std::vector<ast::ptr<ast::Attribute>> attributes;
+		// Is this a declaration with a body (may have fields)?
+		bool body;
+		// Is this type anonymous? (Name can still be set to generated name.)
+		bool anon;
+		// Is this a typed enumeration? Type may be stored in base.
+		bool typed;
+		EnumHiding hiding;
+	};
+
+	struct AggInst_t {
+		TypeData * aggregate = nullptr;
+		ExpressionNode * params = nullptr;
+		bool hoistType;
+	};
+
+	struct Array_t {
+		ExpressionNode * dimension = nullptr;
+		bool isVarLen;
+		bool isStatic;
+	};
+
+	struct Function_t {
+		mutable DeclarationNode * params = nullptr;		// mutables modified in buildKRFunction
+		mutable DeclarationNode * idList = nullptr;		// old-style
+		mutable DeclarationNode * oldDeclList = nullptr;
+		StatementNode * body = nullptr;
+		ExpressionNode * withExprs = nullptr;			// expressions from function's with_clause
+	};
+
+	struct Symbolic_t {
+		const std::string * name = nullptr;
+		bool isTypedef;									// false => TYPEGENname, true => TYPEDEFname
+		DeclarationNode * params = nullptr;
+		ExpressionNode * actuals = nullptr;
+		DeclarationNode * assertions = nullptr;
+	};
+
+	struct Qualified_t {								// qualified type S.T
+		TypeData * parent = nullptr;
+		TypeData * child = nullptr;
+	};
+
+	CodeLocation location;
+
+	Kind kind;
+	TypeData * base;
+	BasicType basictype = NoBasicType;
+	ComplexType complextype = NoComplexType;
+	Signedness signedness = NoSignedness;
+	Length length = NoLength;
+	BuiltinType builtintype = NoBuiltinType;
+
+	ast::CV::Qualifiers qualifiers;
+	DeclarationNode * forall = nullptr;
+
+	Aggregate_t aggregate;
+	AggInst_t aggInst;
+	Array_t array;
+	Function_t function;
+	Symbolic_t symbolic;
+	Qualified_t qualified;
+	DeclarationNode * tuple = nullptr;
+	ExpressionNode * typeexpr = nullptr;
+
+	TypeData( Kind k = Unknown );
+	~TypeData();
+	void print( std::ostream &, int indent = 0 ) const;
+	TypeData * clone() const;
+
+	const std::string * leafName() const;
+
+	TypeData * getLastBase();
+	void setLastBase( TypeData * );
+};
+
+
+TypeData * build_type_qualifier( ast::CV::Qualifiers );
+TypeData * build_basic_type( TypeData::BasicType );
+TypeData * build_complex_type( TypeData::ComplexType );
+TypeData * build_signedness( TypeData::Signedness );
+TypeData * build_builtin_type( TypeData::BuiltinType );
+TypeData * build_length( TypeData::Length );
+TypeData * build_forall( DeclarationNode * );
+TypeData * build_global_scope();
+TypeData * build_qualified_type( TypeData *, TypeData * );
+TypeData * build_typedef( const std::string * name );
+TypeData * build_type_gen( const std::string * name, ExpressionNode * params );
+TypeData * build_vtable_type( TypeData * );
+
+TypeData * addQualifiers( TypeData * ltype, TypeData * rtype );
+TypeData * addType( TypeData * ltype, TypeData * rtype, std::vector<ast::ptr<ast::Attribute>> & );
+TypeData * addType( TypeData * ltype, TypeData * rtype );
+TypeData * cloneBaseType( TypeData * type, TypeData * other );
+TypeData * makeNewBase( TypeData * type );
+
+
+ast::Type * typebuild( const TypeData * );
+TypeData * typeextractAggregate( const TypeData * td, bool toplevel = true );
+ast::CV::Qualifiers buildQualifiers( const TypeData * td );
+ast::Type * buildBasicType( const TypeData * );
+ast::PointerType * buildPointer( const TypeData * );
+ast::ArrayType * buildArray( const TypeData * );
+ast::ReferenceType * buildReference( const TypeData * );
+ast::AggregateDecl * buildAggregate( const TypeData *, std::vector<ast::ptr<ast::Attribute>> );
+ast::BaseInstType * buildComAggInst( const TypeData *, std::vector<ast::ptr<ast::Attribute>> && attributes, ast::Linkage::Spec linkage );
+ast::BaseInstType * buildAggInst( const TypeData * );
+ast::TypeDecl * buildVariable( const TypeData * );
+ast::EnumDecl * buildEnum( const TypeData *, std::vector<ast::ptr<ast::Attribute>> &&, ast::Linkage::Spec );
+ast::TypeInstType * buildSymbolicInst( const TypeData * );
+ast::TupleType * buildTuple( const TypeData * );
+ast::TypeofType * buildTypeof( const TypeData * );
+ast::VTableType * buildVtable( const TypeData * );
+ast::Decl * buildDecl(
+	const TypeData *, const std::string &, ast::Storage::Classes, ast::Expr *,
+	ast::Function::Specs funcSpec, ast::Linkage::Spec, ast::Expr * asmName,
+	ast::Init * init = nullptr, std::vector<ast::ptr<ast::Attribute>> && attributes = std::vector<ast::ptr<ast::Attribute>>() );
+ast::FunctionType * buildFunctionType( const TypeData * );
+void buildKRFunction( const TypeData::Function_t & function );
+
+static inline ast::Type * maybeMoveBuildType( TypeData * type ) {
+	ast::Type * ret = type ? typebuild( type ) : nullptr;
+	delete type;
+	return ret;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/TypedefTable.cc
===================================================================
--- src/Parser/TypedefTable.cc	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,151 +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.
-//
-// TypedefTable.cc --
-//
-// Author           : Peter A. Buhr
-// Created On       : Sat May 16 15:20:13 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 12 06:11:28 2023
-// Update Count     : 276
-//
-
-
-#include "TypedefTable.h"
-
-#include <cassert>										// for assert
-#include <string>										// for string
-#include <iostream>										// for iostream
-
-struct TypeData;
-
-#include "ExpressionNode.h"								// for LabelNode
-#include "ParserTypes.h"								// for Token
-#include "StatementNode.h"								// for CondCtl, ForCtrl
-// This (generated) header must come late as it is missing includes.
-#include "parser.hh"									// for IDENTIFIER, TYPEDEFname, TYPEGENname
-
-using namespace std;
-
-#if 0
-#define debugPrint( code ) code
-
-static const char *kindName( int kind ) {
-	switch ( kind ) {
-	case IDENTIFIER: return "identifier";
-	case TYPEDIMname: return "typedim";
-	case TYPEDEFname: return "typedef";
-	case TYPEGENname: return "typegen";
-	default:
-		cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
-		abort();
-	} // switch
-} // kindName
-#else
-#define debugPrint( code )
-#endif
-
-TypedefTable::~TypedefTable() {
-	if ( ! SemanticErrorThrow && kindTable.currentScope() != 0 ) {
-		cerr << "Error: cfa-cpp internal error, scope failure " << kindTable.currentScope() << endl;
-		abort();
-	} // if
-} // TypedefTable::~TypedefTable
-
-bool TypedefTable::exists( const string & identifier ) const {
-	return kindTable.find( identifier ) != kindTable.end();
-} // TypedefTable::exists
-
-bool TypedefTable::existsCurr( const string & identifier ) const {
-	return kindTable.findAt( kindTable.currentScope() - 1, identifier ) != kindTable.end();
-} // TypedefTable::exists
-
-int TypedefTable::isKind( const string & identifier ) const {
-	KindTable::const_iterator posn = kindTable.find( identifier );
-	// Name lookup defaults to identifier, and then the identifier's kind is set by the parser.
-	if ( posn == kindTable.end() ) return IDENTIFIER;
-	return posn->second;
-} // TypedefTable::isKind
-
-// SKULLDUGGERY: Generate a typedef for the aggregate name so the aggregate does not have to be qualified by
-// "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the
-// name is explicitly used.
-void TypedefTable::makeTypedef( const string & name, int kind, const char * locn __attribute__((unused)) ) {
-//    Check for existence is necessary to handle:
-//        struct Fred {};
-//        void Fred();
-//        void fred() {
-//           struct Fred act; // do not add as type in this scope
-//           Fred();
-//        }
-	debugPrint( cerr << "Make typedef at " << locn << " \"" << name << "\" as " << kindName( kind ) << " scope " << kindTable.currentScope() << endl );
-	if ( ! typedefTable.exists( name ) ) {
-		typedefTable.addToEnclosingScope( name, kind, "MTD" );
-	} // if
-} // TypedefTable::makeTypedef
-
-void TypedefTable::makeTypedef( const string & name, const char * locn __attribute__((unused)) ) {
-	debugPrint( cerr << "Make typedef at " << locn << " \"" << name << " scope " << kindTable.currentScope() << endl );
-	return makeTypedef( name, TYPEDEFname, "makeTypede" );
-} // TypedefTable::makeTypedef
-
-void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
-	KindTable::size_type scope = kindTable.currentScope();
-	debugPrint( cerr << "Adding current at " << locn << " \"" << identifier << "\" as " << kindName( kind ) << " scope " << scope << endl );
-	kindTable.insertAt( scope, identifier, kind );
-} // TypedefTable::addToScope
-
-void TypedefTable::addToEnclosingScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
-	KindTable::size_type scope = kindTable.currentScope() - 1 - kindTable.getNote( kindTable.currentScope() - 1 ).level;
-//	size_type scope = level - kindTable.getNote( kindTable.currentScope() - 1 ).level;
-	debugPrint( cerr << "Adding enclosing at " << locn << " \"" << identifier << "\" as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl );
-	pair< KindTable::iterator, bool > ret = kindTable.insertAt( scope, identifier, kind );
-	if ( ! ret.second ) ret.first->second = kind;		// exists => update
-} // TypedefTable::addToEnclosingScope
-
-void TypedefTable::enterScope() {
-	kindTable.beginScope( (Note){ 0, false } );
-	debugPrint( cerr << "Entering scope " << kindTable.currentScope() << " level " << level << endl; print() );
-} // TypedefTable::enterScope
-
-void TypedefTable::leaveScope() {
-	debugPrint( cerr << "Leaving scope " << kindTable.currentScope() << endl; print() );
-	kindTable.endScope();
-} // TypedefTable::leaveScope
-
-void TypedefTable::up( bool forall ) {
-	level += 1;
-	kindTable.getNote( kindTable.currentScope() ) = (Note){ level, forall || getEnclForall() };
-	debugPrint( cerr << "Up " << " level " << level << " note " << kindTable.getNote( level ).level << ", " << kindTable.getNote( level ).forall << endl; );
-} // TypedefTable::up
-
-void TypedefTable::down() {
-	level -= 1;
-	debugPrint( cerr << "Down " << " level " << level << " note " << kindTable.getNote( level ).level << endl; );
-} // TypedefTable::down
-
-void TypedefTable::print( void ) const {
-	KindTable::size_type scope = kindTable.currentScope();
-	debugPrint( cerr << "[" << scope << "] " << kindTable.getNote( scope ).level << ", " << kindTable.getNote( scope ).forall << ":" );
-	for ( KindTable::const_iterator i = kindTable.begin(); i != kindTable.end(); i++ ) {
-		while ( i.get_level() != scope ) {
-			--scope;
-			debugPrint( cerr << endl << "[" << scope << "] " << kindTable.getNote( scope ).level << ", " << kindTable.getNote( scope ).forall << ":" );
-		} // while
-		debugPrint( cerr << " " << (*i).first << ":" << kindName( (*i).second ) );
-	} // for
-	while ( scope > 0 ) {
-		--scope;
-		debugPrint( cerr << endl << "[" << scope << "] " << kindTable.getNote( scope ).level << ", " << kindTable.getNote( scope ).forall << ":" );
-	} // while
-	debugPrint( cerr << endl );
-} // TypedefTable::print
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/TypedefTable.cpp
===================================================================
--- src/Parser/TypedefTable.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/TypedefTable.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,151 @@
+//
+// 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.
+//
+// TypedefTable.cpp --
+//
+// Author           : Peter A. Buhr
+// Created On       : Sat May 16 15:20:13 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Jul 12 06:11:28 2023
+// Update Count     : 276
+//
+
+
+#include "TypedefTable.hpp"
+
+#include <cassert>										// for assert
+#include <string>										// for string
+#include <iostream>										// for iostream
+
+struct TypeData;
+
+#include "ExpressionNode.hpp"							// for LabelNode
+#include "ParserTypes.hpp"								// for Token
+#include "StatementNode.hpp"							// for CondCtl, ForCtrl
+// This (generated) header must come late as it is missing includes.
+#include "parser.hh"									// for IDENTIFIER, TYPEDEFname, TYPEGENname
+
+using namespace std;
+
+#if 0
+#define debugPrint( code ) code
+
+static const char *kindName( int kind ) {
+	switch ( kind ) {
+	case IDENTIFIER: return "identifier";
+	case TYPEDIMname: return "typedim";
+	case TYPEDEFname: return "typedef";
+	case TYPEGENname: return "typegen";
+	default:
+		cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
+		abort();
+	} // switch
+} // kindName
+#else
+#define debugPrint( code )
+#endif
+
+TypedefTable::~TypedefTable() {
+	if ( ! SemanticErrorThrow && kindTable.currentScope() != 0 ) {
+		cerr << "Error: cfa-cpp internal error, scope failure " << kindTable.currentScope() << endl;
+		abort();
+	} // if
+} // TypedefTable::~TypedefTable
+
+bool TypedefTable::exists( const string & identifier ) const {
+	return kindTable.find( identifier ) != kindTable.end();
+} // TypedefTable::exists
+
+bool TypedefTable::existsCurr( const string & identifier ) const {
+	return kindTable.findAt( kindTable.currentScope() - 1, identifier ) != kindTable.end();
+} // TypedefTable::exists
+
+int TypedefTable::isKind( const string & identifier ) const {
+	KindTable::const_iterator posn = kindTable.find( identifier );
+	// Name lookup defaults to identifier, and then the identifier's kind is set by the parser.
+	if ( posn == kindTable.end() ) return IDENTIFIER;
+	return posn->second;
+} // TypedefTable::isKind
+
+// SKULLDUGGERY: Generate a typedef for the aggregate name so the aggregate does not have to be qualified by
+// "struct". Only generate the typedef, if the name is not in use. The typedef is implicitly (silently) removed if the
+// name is explicitly used.
+void TypedefTable::makeTypedef( const string & name, int kind, const char * locn __attribute__((unused)) ) {
+//    Check for existence is necessary to handle:
+//        struct Fred {};
+//        void Fred();
+//        void fred() {
+//           struct Fred act; // do not add as type in this scope
+//           Fred();
+//        }
+	debugPrint( cerr << "Make typedef at " << locn << " \"" << name << "\" as " << kindName( kind ) << " scope " << kindTable.currentScope() << endl );
+	if ( ! typedefTable.exists( name ) ) {
+		typedefTable.addToEnclosingScope( name, kind, "MTD" );
+	} // if
+} // TypedefTable::makeTypedef
+
+void TypedefTable::makeTypedef( const string & name, const char * locn __attribute__((unused)) ) {
+	debugPrint( cerr << "Make typedef at " << locn << " \"" << name << " scope " << kindTable.currentScope() << endl );
+	return makeTypedef( name, TYPEDEFname, "makeTypede" );
+} // TypedefTable::makeTypedef
+
+void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
+	KindTable::size_type scope = kindTable.currentScope();
+	debugPrint( cerr << "Adding current at " << locn << " \"" << identifier << "\" as " << kindName( kind ) << " scope " << scope << endl );
+	kindTable.insertAt( scope, identifier, kind );
+} // TypedefTable::addToScope
+
+void TypedefTable::addToEnclosingScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
+	KindTable::size_type scope = kindTable.currentScope() - 1 - kindTable.getNote( kindTable.currentScope() - 1 ).level;
+//	size_type scope = level - kindTable.getNote( kindTable.currentScope() - 1 ).level;
+	debugPrint( cerr << "Adding enclosing at " << locn << " \"" << identifier << "\" as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl );
+	pair< KindTable::iterator, bool > ret = kindTable.insertAt( scope, identifier, kind );
+	if ( ! ret.second ) ret.first->second = kind;		// exists => update
+} // TypedefTable::addToEnclosingScope
+
+void TypedefTable::enterScope() {
+	kindTable.beginScope( (Note){ 0, false } );
+	debugPrint( cerr << "Entering scope " << kindTable.currentScope() << " level " << level << endl; print() );
+} // TypedefTable::enterScope
+
+void TypedefTable::leaveScope() {
+	debugPrint( cerr << "Leaving scope " << kindTable.currentScope() << endl; print() );
+	kindTable.endScope();
+} // TypedefTable::leaveScope
+
+void TypedefTable::up( bool forall ) {
+	level += 1;
+	kindTable.getNote( kindTable.currentScope() ) = (Note){ level, forall || getEnclForall() };
+	debugPrint( cerr << "Up " << " level " << level << " note " << kindTable.getNote( level ).level << ", " << kindTable.getNote( level ).forall << endl; );
+} // TypedefTable::up
+
+void TypedefTable::down() {
+	level -= 1;
+	debugPrint( cerr << "Down " << " level " << level << " note " << kindTable.getNote( level ).level << endl; );
+} // TypedefTable::down
+
+void TypedefTable::print( void ) const {
+	KindTable::size_type scope = kindTable.currentScope();
+	debugPrint( cerr << "[" << scope << "] " << kindTable.getNote( scope ).level << ", " << kindTable.getNote( scope ).forall << ":" );
+	for ( KindTable::const_iterator i = kindTable.begin(); i != kindTable.end(); i++ ) {
+		while ( i.get_level() != scope ) {
+			--scope;
+			debugPrint( cerr << endl << "[" << scope << "] " << kindTable.getNote( scope ).level << ", " << kindTable.getNote( scope ).forall << ":" );
+		} // while
+		debugPrint( cerr << " " << (*i).first << ":" << kindName( (*i).second ) );
+	} // for
+	while ( scope > 0 ) {
+		--scope;
+		debugPrint( cerr << endl << "[" << scope << "] " << kindTable.getNote( scope ).level << ", " << kindTable.getNote( scope ).forall << ":" );
+	} // while
+	debugPrint( cerr << endl );
+} // TypedefTable::print
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/TypedefTable.h
===================================================================
--- src/Parser/TypedefTable.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,55 +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.
-//
-// TypedefTable.h --
-//
-// Author           : Peter A. Buhr
-// Created On       : Sat May 16 15:24:36 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 12 06:09:37 2023
-// Update Count     : 118
-//
-
-#pragma once
-
-#include <string>										// for string
-
-#include "Common/ScopedMap.h"							// for ScopedMap
-
-class TypedefTable {
-	struct Note {
-		size_t level;
-		bool forall;
-	};
-	typedef ScopedMap< std::string, int, Note > KindTable;
-	KindTable kindTable;
-	unsigned int level = 0;
-  public:
-	~TypedefTable();
-
-	bool exists( const std::string & identifier ) const;
-	bool existsCurr( const std::string & identifier ) const;
-	int isKind( const std::string & identifier ) const;
-	void makeTypedef( const std::string & name, int kind, const char * );
-	void makeTypedef( const std::string & name, const char * );
-	void addToScope( const std::string & identifier, int kind, const char * );
-	void addToEnclosingScope( const std::string & identifier, int kind, const char * );
-	bool getEnclForall() { return kindTable.getNote( kindTable.currentScope() -  1 ).forall; }
-
-	void enterScope();
-	void leaveScope();
-
-	void up( bool );
-	void down();
-
-	void print( void ) const;
-}; // TypedefTable
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Parser/TypedefTable.hpp
===================================================================
--- src/Parser/TypedefTable.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Parser/TypedefTable.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,55 @@
+//
+// 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.
+//
+// TypedefTable.hpp --
+//
+// Author           : Peter A. Buhr
+// Created On       : Sat May 16 15:24:36 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Jul 12 06:09:37 2023
+// Update Count     : 118
+//
+
+#pragma once
+
+#include <string>										// for string
+
+#include "Common/ScopedMap.hpp"							// for ScopedMap
+
+class TypedefTable {
+	struct Note {
+		size_t level;
+		bool forall;
+	};
+	typedef ScopedMap< std::string, int, Note > KindTable;
+	KindTable kindTable;
+	unsigned int level = 0;
+  public:
+	~TypedefTable();
+
+	bool exists( const std::string & identifier ) const;
+	bool existsCurr( const std::string & identifier ) const;
+	int isKind( const std::string & identifier ) const;
+	void makeTypedef( const std::string & name, int kind, const char * );
+	void makeTypedef( const std::string & name, const char * );
+	void addToScope( const std::string & identifier, int kind, const char * );
+	void addToEnclosingScope( const std::string & identifier, int kind, const char * );
+	bool getEnclForall() { return kindTable.getNote( kindTable.currentScope() -  1 ).forall; }
+
+	void enterScope();
+	void leaveScope();
+
+	void up( bool );
+	void down();
+
+	void print( void ) const;
+}; // TypedefTable
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Parser/lex.ll
===================================================================
--- src/Parser/lex.ll	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ src/Parser/lex.ll	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -44,11 +44,11 @@
 
 #include "config.h"										// configure info
-#include "DeclarationNode.h"                            // for DeclarationNode
-#include "ExpressionNode.h"                             // for LabelNode
-#include "InitializerNode.h"                            // for InitializerNode
-#include "ParseNode.h"
-#include "ParserTypes.h"                                // for Token
-#include "StatementNode.h"                              // for CondCtl, ForCtrl
-#include "TypedefTable.h"
+#include "DeclarationNode.hpp"                          // for DeclarationNode
+#include "ExpressionNode.hpp"                           // for LabelNode
+#include "InitializerNode.hpp"                          // for InitializerNode
+#include "ParseNode.hpp"
+#include "ParserTypes.hpp"                              // for Token
+#include "StatementNode.hpp"                            // for CondCtl, ForCtrl
+#include "TypedefTable.hpp"
 // This (generated) header must come late as it is missing includes.
 #include "parser.hh"                                    // generated info
Index: src/Parser/module.mk
===================================================================
--- src/Parser/module.mk	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ src/Parser/module.mk	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -20,24 +20,28 @@
 
 SRC += \
-       Parser/DeclarationNode.cc \
-       Parser/DeclarationNode.h \
-       Parser/ExpressionNode.cc \
-       Parser/ExpressionNode.h \
-       Parser/InitializerNode.cc \
-       Parser/InitializerNode.h \
+       Parser/DeclarationNode.cpp \
+       Parser/DeclarationNode.hpp \
+       Parser/ExpressionNode.cpp \
+       Parser/ExpressionNode.hpp \
+       Parser/InitializerNode.cpp \
+       Parser/InitializerNode.hpp \
        Parser/lex.ll \
-       Parser/ParseNode.cc \
-       Parser/ParseNode.h \
+       Parser/ParseNode.cpp \
+       Parser/ParseNode.hpp \
        Parser/parser.yy \
-       Parser/ParserTypes.h \
-       Parser/parserutility.h \
+       Parser/ParserTypes.hpp \
+       Parser/parserutility.hpp \
        Parser/RunParser.cpp \
        Parser/RunParser.hpp \
-       Parser/StatementNode.cc \
-       Parser/StatementNode.h \
-       Parser/TypeData.cc \
-       Parser/TypeData.h \
-       Parser/TypedefTable.cc \
-       Parser/TypedefTable.h
+       Parser/StatementNode.cpp \
+       Parser/StatementNode.hpp \
+       Parser/TypeData.cpp \
+       Parser/TypeData.hpp \
+       Parser/TypedefTable.cpp \
+       Parser/TypedefTable.hpp
 
-MOSTLYCLEANFILES += Parser/lex.cc Parser/parser.cc Parser/parser.hh Parser/parser.output
+MOSTLYCLEANFILES += \
+       Parser/lex.cc \
+       Parser/parser.cc \
+       Parser/parser.hh \
+       Parser/parser.output
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ src/Parser/parser.yy	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -48,14 +48,14 @@
 using namespace std;
 
-#include "DeclarationNode.h"                            // for DeclarationNode, ...
-#include "ExpressionNode.h"                             // for ExpressionNode, ...
-#include "InitializerNode.h"                            // for InitializerNode, ...
-#include "ParserTypes.h"
-#include "StatementNode.h"                              // for build_...
-#include "TypedefTable.h"
-#include "TypeData.h"
+#include "DeclarationNode.hpp"                          // for DeclarationNode, ...
+#include "ExpressionNode.hpp"                           // for ExpressionNode, ...
+#include "InitializerNode.hpp"                          // for InitializerNode, ...
+#include "ParserTypes.hpp"
+#include "StatementNode.hpp"                            // for build_...
+#include "TypedefTable.hpp"
+#include "TypeData.hpp"
 #include "AST/Type.hpp"                                 // for BasicType, BasicKind
-#include "Common/SemanticError.h"						// error_str
-#include "Common/utility.h"								// for maybeMoveBuild, maybeBuild, CodeLo...
+#include "Common/SemanticError.hpp"                     // error_str
+#include "Common/Utility.hpp"                           // for maybeMoveBuild, maybeBuild, CodeLo...
 
 // lex uses __null in a boolean context, it's fine.
Index: src/Parser/parserutility.h
===================================================================
--- src/Parser/parserutility.h	(revision e78966e277bce78db1271c91a81aedf78a7627f2)
+++ 	(revision )
@@ -1,41 +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.
-//
-// parserutility.h -- Collected utilities for the parser.
-//
-// Author           : Rodolfo G. Esteves
-// Created On       : Sat May 16 15:31:46 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Apr  4 14:03:00 2023
-// Update Count     : 7
-//
-
-#pragma once
-
-#include "AST/Copy.hpp"            // for shallowCopy
-
-template< typename T >
-static inline auto maybeBuild( T * orig ) -> decltype(orig->build()) {
-	return (orig) ? orig->build() : nullptr;
-}
-
-template< typename T >
-static inline auto maybeMoveBuild( T * orig ) -> decltype(orig->build()) {
-	auto ret = maybeBuild<T>(orig);
-	delete orig;
-	return ret;
-}
-
-template<typename node_t>
-static inline node_t * maybeCopy( node_t const * node ) {
-	return node ? ast::shallowCopy( node ) : nullptr;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
