Index: libcfa/src/exception.c
===================================================================
--- libcfa/src/exception.c	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ libcfa/src/exception.c	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -69,6 +69,6 @@
 
 
-// This macro should be the only thing that needs to change across machines.  Used in the personality function, way down
-// in termination.
+// This macro should be the only thing that needs to change across machines.
+// Used in the personality function, way down in termination.
 // struct _Unwind_Context * -> _Unwind_Reason_Code(*)(exception_t *)
 #define MATCHER_FROM_CONTEXT(ptr_to_context) \
@@ -102,6 +102,7 @@
 }
 
-// Do we control where exceptions get thrown even with concurency?  If not these are not quite thread safe, the cleanup
-// hook has to be added after the node is built but before it is made the top node.
+// Do we control where exceptions get thrown even with concurency?
+// If not these are not quite thread safe, the cleanup hook has to
+// be added after the node is built but before it is made the top node.
 
 void __cfaabi_ehm__try_resume_setup(struct __cfaabi_ehm__try_resume_node * node,
@@ -212,13 +213,14 @@
 	_Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
 
-	// If we reach here it means something happened.  For resumption to work we need to find a way to return back to
-	// here.  Most of them will probably boil down to setting a global flag and making the phase 1 either stop or
-	// fail.  Causing an error on purpose may help avoiding unnecessary work but it might have some weird side
-	// effects.  If we just pretend no handler was found that would work but may be expensive for no reason since we
-	// will always search the whole stack.
+	// If we reach here it means something happened. For resumption to work we need to find a way
+	// to return back to here. Most of them will probably boil down to setting a global flag and
+	// making the phase 1 either stop or fail. Causing an error on purpose may help avoiding
+	// unnecessary work but it might have some weird side effects. If we just pretend no handler
+	// was found that would work but may be expensive for no reason since we will always search
+	// the whole stack.
 
 	if( ret == _URC_END_OF_STACK ) {
-		// No proper handler was found.  This can be handled in several way.  C++ calls std::terminate Here we
-		// force unwind the stack, basically raising a cancellation.
+		// No proper handler was found. This can be handled in many ways, C++ calls std::terminate.
+		// Here we force unwind the stack, basically raising a cancellation.
 		printf("Uncaught exception %p\n", &this_exception_storage);
 
@@ -228,5 +230,5 @@
 	}
 
-	// We did not simply reach the end of the stack without finding a handler.  Something wen't wrong
+	// We did not simply reach the end of the stack without finding a handler. This is an error.
 	printf("UNWIND ERROR %d after raise exception\n", ret);
 	abort();
@@ -254,7 +256,8 @@
 	abort();
 }
-#else
-// This is our personality routine.  For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0".
-// This function will be called twice when unwinding.  Once in the search phased and once in the cleanup phase.
+#else // PIC
+// This is our personality routine. For every stack frame annotated with
+// ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding.
+//  Once in the search phase and once in the cleanup phase.
 _Unwind_Reason_Code __gcfa_personality_v0 (
 		int version, _Unwind_Action actions, unsigned long long exceptionClass,
@@ -264,5 +267,6 @@
 
 	//__cfaabi_dbg_print_safe("CFA: 0x%lx\n", _Unwind_GetCFA(context));
-	__cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
+	__cfaabi_dbg_print_safe("Personality function (%d, %x, %llu, %p, %p):",
+			version, actions, exceptionClass, unwind_exception, context);
 
 	// If we've reached the end of the stack then there is nothing much we can do...
@@ -291,5 +295,5 @@
 	// Get the instuction pointer and a reading pointer into the exception table
 	lsda_header_info lsd_info;
-	const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
+	const unsigned char * cur_ptr = parse_lsda_header(context, lsd, &lsd_info);
 	_Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
 
@@ -302,8 +306,8 @@
 
 		// Decode the common stuff we have in here
-		cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
-		cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
-		cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
-		cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
+		cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
+		cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
+		cur_ptr = read_encoded_value(0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
+		cur_ptr = read_uleb128(cur_ptr, &callsite_action);
 
 		// Have we reach the correct frame info yet?
@@ -316,10 +320,11 @@
 			void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
 			void * ip = (void*)instruction_ptr;
-			__cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
+			__cfaabi_dbg_print_safe("\nfound %p - %p (%p, %p, %p), looking for %p\n",
+					bp, ep, ls, cs, cl, ip);
 #endif // __CFA_DEBUG_PRINT__
 			continue;
 		}
 
-		// Have we gone too far
+		// Have we gone too far?
 		if( lsd_info.Start + callsite_start > instruction_ptr ) {
 			printf(" gone too far");
@@ -331,8 +336,8 @@
 			// Which phase are we in
 			if (actions & _UA_SEARCH_PHASE) {
-				// Search phase, this means we probably found a potential handler and must check if it is a match
-
-				// If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
-				// This doesn't seem to conflict the gcc default behavior
+				// In search phase, these means we found a potential handler we must check.
+
+				// We have arbitrarily decided that 0 means nothing to do and 1 means there is
+				// a potential handler. This doesn't seem to conflict the gcc default behavior.
 				if (callsite_action != 0) {
 					// Now we want to run some code to see if the handler matches
@@ -351,9 +356,6 @@
 					// The current apprach uses one exception table entry per try block
 					_uleb128_t imatcher;
-					// Get the relative offset to the
-					cur_ptr = read_uleb128 (cur_ptr, &imatcher);
-
-					// Get a function pointer from the relative offset and call it
-					// _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;
+					// Get the relative offset to the {...}?
+					cur_ptr = read_uleb128(cur_ptr, &imatcher);
 
 					_Unwind_Reason_Code (*matcher)(exception_t *) =
@@ -414,6 +416,6 @@
 }
 
-// Try statements are hoisted out see comments for details.  With this could probably be unique and simply linked from
-// libcfa but there is one problem left, see the exception table for details
+// Try statements are hoisted out see comments for details. While this could probably be unique
+// and simply linked from libcfa but there is one problem left, see the exception table for details
 __attribute__((noinline))
 void __cfaabi_ehm__try_terminate(void (*try_block)(),
@@ -428,7 +430,6 @@
 	// assembly works.
 
-	// Setup the personality routine
+	// Setup the personality routine and exception table.
 	asm volatile (".cfi_personality 0x3,__gcfa_personality_v0");
-	// Setup the exception table
 	asm volatile (".cfi_lsda 0x3, .LLSDACFA2");
 
@@ -442,5 +443,5 @@
 	asm volatile goto ("" : : : : CATCH );
 
-	// Normal return
+	// Normal return for when there is no throw.
 	return;
 
@@ -459,26 +460,33 @@
 }
 
-// Exception table data we need to generate.  While this is almost generic, the custom data refers to foo_try_match try
-// match, which is no way generic.  Some more works need to be done if we want to have a single call to the try routine.
+// Exception table data we need to generate. While this is almost generic, the custom data refers
+// to {*}try_terminate, which is no way generic. Some more works need to be done if we want to
+// have a single call to the try routine.
 
 #if defined( __i386 ) || defined( __x86_64 )
 asm (
-	//HEADER
+	// HEADER
 	".LFECFA1:\n"
 	"	.globl	__gcfa_personality_v0\n"
 	"	.section	.gcc_except_table,\"a\",@progbits\n"
-	".LLSDACFA2:\n"							//TABLE header
+	// TABLE HEADER (important field is the BODY length at the end)
+	".LLSDACFA2:\n"
 	"	.byte	0xff\n"
 	"	.byte	0xff\n"
 	"	.byte	0x1\n"
-	"	.uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"		// BODY length
-	// Body uses language specific data and therefore could be modified arbitrarily
-	".LLSDACSBCFA2:\n"						// BODY start
-	"	.uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"		// Handled area start  (relative to start of function)
-	"	.uleb128 .TRYEND-.TRYSTART\n"				// Handled area length
-	"	.uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"				// Hanlder landing pad adress  (relative to start of function)
-	"	.uleb128 1\n"						// Action code, gcc seems to use always 0
-	".LLSDACSECFA2:\n"						// BODY end
-	"	.text\n"							// TABLE footer
+	"	.uleb128 .LLSDACSECFA2-.LLSDACSBCFA2\n"
+	// BODY (language specific data)
+	".LLSDACSBCFA2:\n"
+	//	Handled area start (relative to start of function)
+	"	.uleb128 .TRYSTART-__cfaabi_ehm__try_terminate\n"
+	//	Handled area length
+	"	.uleb128 .TRYEND-.TRYSTART\n"
+	//	Handler landing pad address (relative to start of function)
+	"	.uleb128 .CATCH-__cfaabi_ehm__try_terminate\n"
+	//	Action code, gcc seems to always use 0.
+	"	.uleb128 1\n"
+	// TABLE FOOTER
+	".LLSDACSECFA2:\n"
+	"	.text\n"
 	"	.size	__cfaabi_ehm__try_terminate, .-__cfaabi_ehm__try_terminate\n"
 	"	.ident	\"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
@@ -486,3 +494,3 @@
 );
 #endif // __i386 || __x86_64
-#endif //PIC
+#endif // PIC
Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ libcfa/src/heap.cfa	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Dec  4 21:42:46 2019
-// Update Count     : 646
+// Last Modified On : Sun Dec  8 21:01:31 2019
+// Update Count     : 647
 //
 
@@ -332,10 +332,9 @@
 
 
-// #comment TD : Is this the samething as Out-of-Memory?
-static inline void noMemory() {
-	abort( "Heap memory exhausted at %zu bytes.\n"
-		   "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
-		   ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
-} // noMemory
+// static inline void noMemory() {
+// 	abort( "Heap memory exhausted at %zu bytes.\n"
+// 		   "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
+// 		   ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
+// } // noMemory
 
 
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/AST/Convert.cpp	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Thu May 09 15::37::05 2019
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jul 25 22:21:46 2019
-// Update Count     : 13
+// Last Modified On : Tue Dec 10 22:20:10 2019
+// Update Count     : 32
 //
 
@@ -245,5 +245,5 @@
 		auto decl = new StructDecl(
 			node->name,
-			node->kind,
+			(AggregateDecl::Aggregate)node->kind,
 			get<Attribute>().acceptL( node->attributes ),
 			LinkageSpec::Spec( node->linkage.val )
@@ -675,19 +675,6 @@
 
 	const ast::Expr * visit( const ast::KeywordCastExpr * node ) override final {
-		KeywordCastExpr::Target castTarget = KeywordCastExpr::NUMBER_OF_TARGETS;
-		switch (node->target) {
-			case ast::KeywordCastExpr::Coroutine:
-				castTarget = KeywordCastExpr::Coroutine;
-				break;
-			case ast::KeywordCastExpr::Thread:
-				castTarget = KeywordCastExpr::Thread;
-				break;
-			case ast::KeywordCastExpr::Monitor:
-				castTarget = KeywordCastExpr::Monitor;
-				break;
-			default:
-				break;
-		}
-		assert ( castTarget < KeywordCastExpr::NUMBER_OF_TARGETS );
+		AggregateDecl::Aggregate castTarget = (AggregateDecl::Aggregate)node->target;
+		assert( AggregateDecl::Generator <= castTarget && castTarget <= AggregateDecl::Thread );
 		auto expr = visitBaseExpr( node,
 			new KeywordCastExpr(
@@ -1504,5 +1491,5 @@
 			old->location,
 			old->name,
-			old->kind,
+			(ast::AggregateDecl::Aggregate)old->kind,
 			GET_ACCEPT_V(attributes, Attribute),
 			{ old->linkage.val }
@@ -2045,20 +2032,7 @@
 	}
 
-	virtual void visit( const KeywordCastExpr * old) override final {
-		ast::KeywordCastExpr::Target castTarget = ast::KeywordCastExpr::NUMBER_OF_TARGETS;
-		switch (old->target) {
-			case KeywordCastExpr::Coroutine:
-				castTarget = ast::KeywordCastExpr::Coroutine;
-				break;
-			case KeywordCastExpr::Thread:
-				castTarget = ast::KeywordCastExpr::Thread;
-				break;
-			case KeywordCastExpr::Monitor:
-				castTarget = ast::KeywordCastExpr::Monitor;
-				break;
-			default:
-				break;
-		}
-		assert ( castTarget < ast::KeywordCastExpr::NUMBER_OF_TARGETS );
+	virtual void visit( const KeywordCastExpr * old ) override final {
+		ast::AggregateDecl::Aggregate castTarget = (ast::AggregateDecl::Aggregate)old->target;
+		assert( ast::AggregateDecl::Generator <= castTarget && castTarget <= ast::AggregateDecl::Thread );
 		this->node = visitBaseExpr( old,
 			new ast::KeywordCastExpr(
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/AST/Decl.cpp	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Thu May 9 10:00:00 2019
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Thu May 9 10:00:00 2019
-// Update Count     : 1
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 16:41:39 2019
+// Update Count     : 18
 //
 
@@ -18,5 +18,4 @@
 #include <cassert>             // for assert, strict_dynamic_cast
 #include <iostream>
-#include <string>
 #include <unordered_map>
 
@@ -56,14 +55,14 @@
 // --- TypeDecl
 
-std::string TypeDecl::typeString() const {
-	static const std::string kindNames[] = { "object type", "function type", "tuple type" };
+const char * TypeDecl::typeString() const {
+	static const char * kindNames[] = { "sized object type", "sized function type", "sized tuple type" };
 	assertf( sizeof(kindNames)/sizeof(kindNames[0]) == DeclarationNode::NoTypeClass-1,
 		"typeString: kindNames is out of sync." );
 	assertf( kind < sizeof(kindNames)/sizeof(kindNames[0]), "TypeDecl's kind is out of bounds." );
-	return (sized ? "sized " : "") + kindNames[ kind ];
+	return sized ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0'
 }
 
-std::string TypeDecl::genTypeString() const {
-	static const std::string kindNames[] = { "dtype", "ftype", "ttype" };
+const char * TypeDecl::genTypeString() const {
+	static const char * kindNames[] = { "dtype", "ftype", "ttype" };
 	assertf( sizeof(kindNames)/sizeof(kindNames[0]) == DeclarationNode::NoTypeClass-1, "genTypeString: kindNames is out of sync." );
 	assertf( kind < sizeof(kindNames)/sizeof(kindNames[0]), "TypeDecl's kind is out of bounds." );
@@ -73,4 +72,13 @@
 std::ostream & operator<< ( std::ostream & out, const TypeDecl::Data & data ) {
 	return out << data.kind << ", " << data.isComplete;
+}
+
+// --- AggregateDecl
+
+// These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
+static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
+
+const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
+	return aggregateNames[aggr];
 }
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/AST/Decl.hpp	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Thu May 9 10:00:00 2019
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Thu May 9 10:00:00 2019
-// Update Count     : 1
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 08:20:20 2019
+// Update Count     : 16
 //
 
@@ -154,5 +154,5 @@
 
 	/// Produces a name for the kind of alias
-	virtual std::string typeString() const = 0;
+	virtual const char * typeString() const = 0;
 
 private:
@@ -190,7 +190,7 @@
 	  init( i ) {}
 
-	std::string typeString() const override;
+	const char * typeString() const override;
 	/// Produces a name for generated code
-	std::string genTypeString() const;
+	const char * genTypeString() const;
 
 	/// convenience accessor to match Type::isComplete()
@@ -212,5 +212,5 @@
 	: NamedTypeDecl( loc, name, storage, b, spec ) {}
 
-	std::string typeString() const override { return "typedef"; }
+	const char * typeString() const override { return "typedef"; }
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
@@ -223,4 +223,7 @@
 class AggregateDecl : public Decl {
 public:
+	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
+	static const char * aggrString( Aggregate aggr );
+
 	std::vector<ptr<Decl>> members;
 	std::vector<ptr<TypeDecl>> params;
@@ -237,5 +240,5 @@
 
 	/// Produces a name for the kind of aggregate
-	virtual std::string typeString() const = 0;
+	virtual const char * typeString() const = 0;
 
 private:
@@ -247,18 +250,18 @@
 class StructDecl final : public AggregateDecl {
 public:
-	DeclarationNode::Aggregate kind;
+	Aggregate kind;
 
 	StructDecl( const CodeLocation& loc, const std::string& name,
-		DeclarationNode::Aggregate kind = DeclarationNode::Struct,
+		Aggregate kind = Struct,
 		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall )
 	: AggregateDecl( loc, name, std::move(attrs), linkage ), kind( kind ) {}
 
-	bool is_coroutine() { return kind == DeclarationNode::Coroutine; }
-	bool is_monitor() { return kind == DeclarationNode::Monitor; }
-	bool is_thread() { return kind == DeclarationNode::Thread; }
-
-	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
-
-	std::string typeString() const override { return "struct"; }
+	bool is_coroutine() { return kind == Coroutine; }
+	bool is_monitor() { return kind == Monitor; }
+	bool is_thread() { return kind == Thread; }
+
+	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+
+	const char * typeString() const override { return aggrString( kind ); }
 
 private:
@@ -276,5 +279,5 @@
 	const Decl * accept( Visitor& v ) const override { return v.visit( this ); }
 
-	std::string typeString() const override { return "union"; }
+	const char * typeString() const override { return aggrString( Union ); }
 
 private:
@@ -295,5 +298,5 @@
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
 
-	std::string typeString() const override { return "enum"; }
+	const char * typeString() const override { return aggrString( Enum ); }
 
 private:
@@ -314,5 +317,5 @@
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
 
-	std::string typeString() const override { return "trait"; }
+	const char * typeString() const override { return "trait"; }
 
 private:
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/AST/Expr.cpp	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Wed May 15 17:00:00 2019
-// Last Modified By : Andrew Beach
+// Last Modified By : Peter A. Buhr
 // Created On       : Thr Jun 13 13:38:00 2019
-// Update Count     : 2
+// Update Count     : 6
 //
 
@@ -141,13 +141,6 @@
 // --- KeywordCastExpr
 
-const std::string & KeywordCastExpr::targetString() const {
-	static const std::string targetStrs[] = {
-		"coroutine", "thread", "monitor"
-	};
-	static_assert(
-		(sizeof(targetStrs) / sizeof(targetStrs[0])) == ((unsigned long)NUMBER_OF_TARGETS),
-		"Each KeywordCastExpr::Target should have a corresponding string representation"
-	);
-	return targetStrs[(unsigned long)target];
+const char * KeywordCastExpr::targetString() const {
+	return AggregateDecl::aggrString( target );
 }
 
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/AST/Expr.hpp	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Fri May 10 10:30:00 2019
-// Last Modified By : Aaron B. Moss
+// Last Modified By : Peter A. Buhr
 // Created On       : Fri May 10 10:30:00 2019
-// Update Count     : 1
+// Update Count     : 7
 //
 
@@ -26,4 +26,5 @@
 #include "Fwd.hpp"        // for UniqueId
 #include "Label.hpp"
+#include "Decl.hpp"
 #include "ParseNode.hpp"
 #include "Visitor.hpp"
@@ -300,11 +301,11 @@
 public:
 	ptr<Expr> arg;
-	enum Target { Coroutine, Thread, Monitor, NUMBER_OF_TARGETS } target;
-
-	KeywordCastExpr( const CodeLocation & loc, const Expr * a, Target t )
+	ast::AggregateDecl::Aggregate target;
+
+	KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t )
 	: Expr( loc ), arg( a ), target( t ) {}
 
 	/// Get a name for the target type
-	const std::string& targetString() const;
+	const char * targetString() const;
 
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/Concurrency/Keywords.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -11,5 +11,5 @@
 // Last Modified By :
 // Last Modified On :
-// Update Count     : 5
+// Update Count     : 9
 //
 
@@ -53,5 +53,5 @@
 	  public:
 
-	  	ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, KeywordCastExpr::Target cast_target ) :
+	  	ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) :
 		  type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
 
@@ -76,5 +76,5 @@
 		const std::string context_error;
 		bool needs_main;
-		KeywordCastExpr::Target cast_target;
+		AggregateDecl::Aggregate cast_target;
 
 		StructDecl   * type_decl = nullptr;
@@ -101,5 +101,5 @@
 			"thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
 			true,
-			KeywordCastExpr::Thread
+			AggregateDecl::Thread
 		)
 		{}
@@ -133,5 +133,5 @@
 			"coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
 			true,
-			KeywordCastExpr::Coroutine
+			AggregateDecl::Coroutine
 		)
 		{}
@@ -165,5 +165,5 @@
 			"monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
 			false,
-			KeywordCastExpr::Monitor
+			AggregateDecl::Monitor
 		)
 		{}
Index: src/Concurrency/Waitfor.cc
===================================================================
--- src/Concurrency/Waitfor.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/Concurrency/Waitfor.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -11,5 +11,5 @@
 // Last Modified By :
 // Last Modified On :
-// Update Count     : 7
+// Update Count     : 10
 //
 
@@ -23,4 +23,5 @@
 #include "Common/PassVisitor.h"    // for PassVisitor
 #include "Common/SemanticError.h"  // for SemanticError
+#include "Common/UniqueName.h"	   // for UniqueName
 #include "Common/utility.h"        // for deleteAll, map_range
 #include "CodeGen/OperatorTable.h" // for isConstructor
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/Parser/DeclarationNode.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 12:34:05 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jul 25 22:17:10 2019
-// Update Count     : 1116
+// Last Modified On : Wed Dec 11 07:40:14 2019
+// Update Count     : 1123
 //
 
@@ -47,5 +47,4 @@
 const char * DeclarationNode::signednessNames[] = { "signed", "unsigned", "NoSignednessNames" };
 const char * DeclarationNode::lengthNames[] = { "short", "long", "long long", "NoLengthNames" };
-const char * DeclarationNode::aggregateNames[] = { "struct", "union", "trait", "coroutine", "monitor", "thread", "NoAggregateNames" };
 const char * DeclarationNode::typeClassNames[] = { "otype", "dtype", "ftype", "NoTypeClassNames" };
 const char * DeclarationNode::builtinTypeNames[] = { "__builtin_va_list", "__auto_type", "zero_t", "one_t", "NoBuiltinTypeNames" };
@@ -267,5 +266,5 @@
 }
 
-DeclarationNode * DeclarationNode::newAggregate( Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
+DeclarationNode * DeclarationNode::newAggregate( AggregateDecl::Aggregate kind, const string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ) {
 	DeclarationNode * newnode = new DeclarationNode;
 	newnode->type = new TypeData( TypeData::Aggregate );
@@ -328,5 +327,5 @@
 	newnode->type = new TypeData( TypeData::Aggregate );
 	newnode->type->aggregate.name = name;
-	newnode->type->aggregate.kind = Trait;
+	newnode->type->aggregate.kind = AggregateDecl::Trait;
 	newnode->type->aggregate.params = params;
 	newnode->type->aggregate.fields = asserts;
@@ -338,5 +337,5 @@
 	newnode->type = new TypeData( TypeData::AggregateInst );
 	newnode->type->aggInst.aggregate = new TypeData( TypeData::Aggregate );
-	newnode->type->aggInst.aggregate->aggregate.kind = Trait;
+	newnode->type->aggInst.aggregate->aggregate.kind = AggregateDecl::Trait;
 	newnode->type->aggInst.aggregate->aggregate.name = name;
 	newnode->type->aggInst.params = params;
Index: src/Parser/ExpressionNode.cc
===================================================================
--- src/Parser/ExpressionNode.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/Parser/ExpressionNode.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 13:17:07 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Aug  4 20:57:55 2019
-// Update Count     : 978
+// Last Modified On : Tue Dec 10 23:01:47 2019
+// Update Count     : 980
 //
 
@@ -434,5 +434,5 @@
 } // build_cast
 
-Expression * build_keyword_cast( KeywordCastExpr::Target target, ExpressionNode * expr_node ) {
+Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node ) {
 	return new KeywordCastExpr( maybeMoveBuild< Expression >(expr_node), target );
 }
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/Parser/ParseNode.h	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 13:28:16 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jul 25 22:17:10 2019
-// Update Count     : 876
+// Last Modified On : Wed Dec 11 07:40:07 2019
+// Update Count     : 882
 //
 
@@ -29,4 +29,5 @@
 #include "Common/utility.h"        // for maybeClone, maybeBuild
 #include "Parser/LinkageSpec.h"    // for Spec
+#include "SynTree/Declaration.h"   // for Aggregate
 #include "SynTree/Expression.h"    // for Expression, ConstantExpr (ptr only)
 #include "SynTree/Label.h"         // for Label
@@ -184,5 +185,5 @@
 
 Expression * build_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
-Expression * build_keyword_cast( KeywordCastExpr::Target target, ExpressionNode * expr_node );
+Expression * build_keyword_cast( AggregateDecl::Aggregate target, ExpressionNode * expr_node );
 Expression * build_virtual_cast( DeclarationNode * decl_node, ExpressionNode * expr_node );
 Expression * build_fieldSel( ExpressionNode * expr_node, Expression * member );
@@ -217,6 +218,4 @@
 	enum Length { Short, Long, LongLong, NoLength };
 	static const char * lengthNames[];
-	enum Aggregate { Struct, Union, Exception, Trait, Coroutine, Monitor, Thread, NoAggregate };
-	static const char * aggregateNames[];
 	enum TypeClass { Otype, Dtype, Ftype, Ttype, NoTypeClass };
 	static const char * typeClassNames[];
@@ -237,5 +236,5 @@
 	static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );
 	static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
-	static DeclarationNode * newAggregate( Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
+	static DeclarationNode * newAggregate( AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
 	static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body );
 	static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/Parser/TypeData.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:12:51 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Feb 13 18:16:23 2019
-// Update Count     : 649
+// Last Modified On : Wed Dec 11 07:48:33 2019
+// Update Count     : 659
 //
 
@@ -67,5 +67,5 @@
 	  case Aggregate:
 		// aggregate = new Aggregate_t;
-		aggregate.kind = DeclarationNode::NoAggregate;
+		aggregate.kind = AggregateDecl::NoAggregate;
 		aggregate.name = nullptr;
 		aggregate.params = nullptr;
@@ -345,5 +345,5 @@
 		break;
 	  case Aggregate:
-		os << DeclarationNode::aggregateNames[ aggregate.kind ] << ' ' << *aggregate.name << endl;
+		os << AggregateDecl::aggrString( aggregate.kind ) << ' ' << *aggregate.name << endl;
 		if ( aggregate.params ) {
 			os << string( indent + 2, ' ' ) << "with type parameters" << endl;
@@ -768,16 +768,16 @@
 	AggregateDecl * at;
 	switch ( td->aggregate.kind ) {
-	  case DeclarationNode::Struct:
-	  case DeclarationNode::Coroutine:
-	  case DeclarationNode::Monitor:
-	  case DeclarationNode::Thread:
+	  case AggregateDecl::Struct:
+	  case AggregateDecl::Coroutine:
+	  case AggregateDecl::Monitor:
+	  case AggregateDecl::Thread:
 		at = new StructDecl( *td->aggregate.name, td->aggregate.kind, attributes, linkage );
 		buildForall( td->aggregate.params, at->get_parameters() );
 		break;
-	  case DeclarationNode::Union:
+	  case AggregateDecl::Union:
 		at = new UnionDecl( *td->aggregate.name, attributes, linkage );
 		buildForall( td->aggregate.params, at->get_parameters() );
 		break;
-	  case DeclarationNode::Trait:
+	  case AggregateDecl::Trait:
 		at = new TraitDecl( *td->aggregate.name, attributes, linkage );
 		buildList( td->aggregate.params, at->get_parameters() );
@@ -809,14 +809,14 @@
 			  AggregateDecl * typedecl = buildAggregate( type, attributes, linkage );
 			  switch ( type->aggregate.kind ) {
-				case DeclarationNode::Struct:
-				case DeclarationNode::Coroutine:
-				case DeclarationNode::Monitor:
-				case DeclarationNode::Thread:
+				case AggregateDecl::Struct:
+				case AggregateDecl::Coroutine:
+				case AggregateDecl::Monitor:
+				case AggregateDecl::Thread:
 				  ret = new StructInstType( buildQualifiers( type ), (StructDecl *)typedecl );
 				  break;
-				case DeclarationNode::Union:
+				case AggregateDecl::Union:
 				  ret = new UnionInstType( buildQualifiers( type ), (UnionDecl *)typedecl );
 				  break;
-				case DeclarationNode::Trait:
+				case AggregateDecl::Trait:
 				  assert( false );
 				  //ret = new TraitInstType( buildQualifiers( type ), (TraitDecl *)typedecl );
@@ -827,14 +827,14 @@
 		  } else {
 			  switch ( type->aggregate.kind ) {
-				case DeclarationNode::Struct:
-				case DeclarationNode::Coroutine:
-				case DeclarationNode::Monitor:
-				case DeclarationNode::Thread:
+				case AggregateDecl::Struct:
+				case AggregateDecl::Coroutine:
+				case AggregateDecl::Monitor:
+				case AggregateDecl::Thread:
 				  ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
 				  break;
-				case DeclarationNode::Union:
+				case AggregateDecl::Union:
 				  ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
 				  break;
-				case DeclarationNode::Trait:
+				case AggregateDecl::Trait:
 				  ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
 				  break;
@@ -863,14 +863,14 @@
 	  case TypeData::Aggregate: {
 		  switch ( type->aggregate.kind ) {
-			case DeclarationNode::Struct:
-			case DeclarationNode::Coroutine:
-			case DeclarationNode::Monitor:
-			case DeclarationNode::Thread:
+			case AggregateDecl::Struct:
+			case AggregateDecl::Coroutine:
+			case AggregateDecl::Monitor:
+			case AggregateDecl::Thread:
 			  ret = new StructInstType( buildQualifiers( type ), *type->aggregate.name );
 			  break;
-			case DeclarationNode::Union:
+			case AggregateDecl::Union:
 			  ret = new UnionInstType( buildQualifiers( type ), *type->aggregate.name );
 			  break;
-			case DeclarationNode::Trait:
+			case AggregateDecl::Trait:
 			  ret = new TraitInstType( buildQualifiers( type ), *type->aggregate.name );
 			  break;
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/Parser/TypeData.h	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:18:36 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Nov  1 20:56:46 2018
-// Update Count     : 196
+// Last Modified On : Tue Dec 10 23:01:07 2019
+// Update Count     : 198
 //
 
@@ -30,5 +30,5 @@
 
 	struct Aggregate_t {
-		DeclarationNode::Aggregate kind;
+		AggregateDecl::Aggregate kind;
 		const std::string * name = nullptr;
 		DeclarationNode * params = nullptr;
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/Parser/parser.yy	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Dec  7 10:43:44 2019
-// Update Count     : 4394
+// Last Modified On : Thu Dec 12 17:54:22 2019
+// Update Count     : 4404
 //
 
@@ -51,4 +51,5 @@
 using namespace std;
 
+#include "SynTree/Declaration.h"
 #include "ParseNode.h"
 #include "TypedefTable.h"
@@ -211,16 +212,4 @@
 } // forCtrl
 
-KeywordCastExpr::Target Aggregate2Target( DeclarationNode::Aggregate aggr ) {
-	KeywordCastExpr::Target target;
-	switch ( aggr ) {
-	  case DeclarationNode::Coroutine: target = KeywordCastExpr::Coroutine; break;
-	  case DeclarationNode::Monitor: target = KeywordCastExpr::Monitor; break;
-	  case DeclarationNode::Thread: target = KeywordCastExpr::Thread; break;
-	  default: abort();
-	} // switch
-	return target;
-} // Aggregate2Target
-
-
 bool forall = false, yyy = false;						// aggregate have one or more forall qualifiers ?
 
@@ -248,5 +237,5 @@
 	ExpressionNode * en;
 	DeclarationNode * decl;
-	DeclarationNode::Aggregate aggKey;
+	AggregateDecl::Aggregate aggKey;
 	DeclarationNode::TypeClass tclass;
 	StatementNode * sn;
@@ -662,5 +651,5 @@
 		{ $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
 	| postfix_expression '.' aggregate_control
-		{ $$ = new ExpressionNode( build_keyword_cast( Aggregate2Target( $3 ), $1 ) ); }
+		{ $$ = new ExpressionNode( build_keyword_cast( $3, $1 ) ); }
 	| postfix_expression ARROW identifier
 		{ $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); }
@@ -807,5 +796,5 @@
 		{ $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
 	| '(' aggregate_control '&' ')' cast_expression		// CFA
-		{ $$ = new ExpressionNode( build_keyword_cast( Aggregate2Target( $2 ), $5 ) ); }
+		{ $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
 		// VIRTUAL cannot be opt because of look ahead issues
 	| '(' VIRTUAL ')' cast_expression					// CFA
@@ -1201,4 +1190,7 @@
 		{ $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
 						OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
+	| '=' comma_expression									// CFA
+		{ $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
+						OperKinds::LEThan, $2->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
 	| comma_expression inclexcl comma_expression		// CFA
 		{ $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
@@ -1208,4 +1200,7 @@
 		{ $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
 						OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
+	| comma_expression ';' '=' comma_expression				// CFA
+		{ $$ = forCtrl( $4, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
+						OperKinds::LEThan, $4->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
 	| comma_expression ';' comma_expression inclexcl comma_expression // CFA
 		{ $$ = forCtrl( $3, $1, $3->clone(), $4, $5, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
@@ -2071,20 +2066,20 @@
 aggregate_data:
 	STRUCT
-		{ yyy = true; $$ = DeclarationNode::Struct; }
+		{ yyy = true; $$ = AggregateDecl::Struct; }
 	| UNION
-		{ yyy = true; $$ = DeclarationNode::Union; }
+		{ yyy = true; $$ = AggregateDecl::Union; }
 	| EXCEPTION											// CFA
-		{ yyy = true; $$ = DeclarationNode::Exception; }
+		{ yyy = true; $$ = AggregateDecl::Exception; }
 	;
 
 aggregate_control:										// CFA
 	GENERATOR
-		{ yyy = true; $$ = DeclarationNode::Coroutine; }
+		{ yyy = true; $$ = AggregateDecl::Coroutine; }
 	| COROUTINE
-		{ yyy = true; $$ = DeclarationNode::Coroutine; }
+		{ yyy = true; $$ = AggregateDecl::Coroutine; }
 	| MONITOR
-		{ yyy = true; $$ = DeclarationNode::Monitor; }
+		{ yyy = true; $$ = AggregateDecl::Monitor; }
 	| THREAD
-		{ yyy = true; $$ = DeclarationNode::Thread; }
+		{ yyy = true; $$ = AggregateDecl::Thread; }
 	;
 
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SymTab/Validate.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 21:50:04 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Aug  7 6:42:00 2019
-// Update Count     : 360
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue Dec 10 22:22:01 2019
+// Update Count     : 362
 //
 
@@ -1049,5 +1049,5 @@
 		Type * designatorType = tyDecl->base->stripDeclarator();
 		if ( StructInstType * aggDecl = dynamic_cast< StructInstType * >( designatorType ) ) {
-			declsToAddBefore.push_back( new StructDecl( aggDecl->name, DeclarationNode::Struct, noAttributes, tyDecl->linkage ) );
+			declsToAddBefore.push_back( new StructDecl( aggDecl->name, AggregateDecl::Struct, noAttributes, tyDecl->linkage ) );
 		} else if ( UnionInstType * aggDecl = dynamic_cast< UnionInstType * >( designatorType ) ) {
 			declsToAddBefore.push_back( new UnionDecl( aggDecl->name, noAttributes, tyDecl->linkage ) );
Index: src/SynTree/AggregateDecl.cc
===================================================================
--- src/SynTree/AggregateDecl.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SynTree/AggregateDecl.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 23:56:39 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri Aug  4 14:22:00 2017
-// Update Count     : 22
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 16:31:55 2019
+// Update Count     : 29
 //
 
@@ -21,7 +21,15 @@
 #include "Common/utility.h"      // for printAll, cloneAll, deleteAll
 #include "Declaration.h"         // for AggregateDecl, TypeDecl, Declaration
+#include "Initializer.h"
 #include "Parser/LinkageSpec.h"  // for Spec, linkageName, Cforall
 #include "Type.h"                // for Type, Type::StorageClasses
 
+
+// These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
+static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
+
+const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
+	return aggregateNames[aggr];
+}
 
 AggregateDecl::AggregateDecl( const std::string &name, const std::list< Attribute * > & attributes, LinkageSpec::Spec linkage ) : Parent( name, Type::StorageClasses(), linkage ), body( false ), attributes( attributes ) {
@@ -78,11 +86,11 @@
 }
 
-std::string StructDecl::typeString() const { return "struct"; }
+const char * StructDecl::typeString() const { return aggrString( kind ); }
 
-std::string UnionDecl::typeString() const { return "union"; }
+const char * UnionDecl::typeString() const { return aggrString( Union ); }
 
-std::string EnumDecl::typeString() const { return "enum"; }
+const char * EnumDecl::typeString() const { return aggrString( Enum ); }
 
-std::string TraitDecl::typeString() const { return "trait"; }
+const char * TraitDecl::typeString() const { return aggrString( Trait ); }
 
 bool EnumDecl::valueOf( Declaration * enumerator, long long int & value ) {
Index: src/SynTree/Declaration.cc
===================================================================
--- src/SynTree/Declaration.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SynTree/Declaration.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Aug  9 14:38:00 2017
-// Update Count     : 25
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 16:39:56 2019
+// Update Count     : 36
 //
 
@@ -24,6 +24,8 @@
 #include "SynTree/Statement.h"       // for AsmStmt
 #include "SynTree/SynTree.h"         // for UniqueId
+#include "SynTree/Expression.h"
 #include "Type.h"                    // for Type, Type::StorageClasses
 
+// To canonicalize declarations
 static UniqueId lastUniqueId = 0;
 
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SynTree/Declaration.h	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Thr May  2 10:47:00 2019
-// Update Count     : 135
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 16:48:20 2019
+// Update Count     : 149
 //
 
@@ -25,5 +25,4 @@
 #include "Mutator.h"             // for Mutator
 #include "Parser/LinkageSpec.h"  // for Spec, Cforall
-#include "Parser/ParseNode.h"    // for DeclarationNode, DeclarationNode::Ag...
 #include "SynTree.h"             // for UniqueId
 #include "SynTree/Type.h"        // for Type, Type::StorageClasses, Type::Fu...
@@ -194,5 +193,5 @@
 	std::list< DeclarationWithType* >& get_assertions() { return assertions; }
 
-	virtual std::string typeString() const = 0;
+	virtual const char * typeString() const = 0;
 
 	virtual NamedTypeDecl *clone() const override = 0;
@@ -237,6 +236,6 @@
 	TypeDecl * set_sized( bool newValue ) { sized = newValue; return this; }
 
-	virtual std::string typeString() const override;
-	virtual std::string genTypeString() const;
+	virtual const char * typeString() const override;
+	virtual const char * genTypeString() const;
 
 	virtual TypeDecl *clone() const override { return new TypeDecl( *this ); }
@@ -257,5 +256,5 @@
 	TypedefDecl( const TypedefDecl &other ) : Parent( other ) {}
 
-	virtual std::string typeString() const override;
+	virtual const char * typeString() const override;
 
 	virtual TypedefDecl *clone() const override { return new TypedefDecl( *this ); }
@@ -269,4 +268,7 @@
 	typedef Declaration Parent;
   public:
+	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
+	static const char * aggrString( Aggregate aggr );
+
 	std::list<Declaration*> members;
 	std::list<TypeDecl*> parameters;
@@ -291,5 +293,5 @@
 	virtual void printShort( std::ostream &os, Indenter indent = {} ) const override;
   protected:
-	virtual std::string typeString() const = 0;
+	virtual const char * typeString() const = 0;
 };
 
@@ -297,10 +299,10 @@
 	typedef AggregateDecl Parent;
   public:
-	StructDecl( const std::string &name, DeclarationNode::Aggregate kind = DeclarationNode::Struct, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall ) : Parent( name, attributes, linkage ), kind( kind ) {}
+	StructDecl( const std::string &name, Aggregate kind = Struct, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall ) : Parent( name, attributes, linkage ), kind( kind ) {}
 	StructDecl( const StructDecl &other ) : Parent( other ), kind( other.kind ) {}
 
-	bool is_coroutine() { return kind == DeclarationNode::Coroutine; }
-	bool is_monitor() { return kind == DeclarationNode::Monitor; }
-	bool is_thread() { return kind == DeclarationNode::Thread; }
+	bool is_coroutine() { return kind == Coroutine; }
+	bool is_monitor() { return kind == Monitor; }
+	bool is_thread() { return kind == Thread; }
 
 	virtual StructDecl *clone() const override { return new StructDecl( *this ); }
@@ -308,7 +310,7 @@
 	virtual void accept( Visitor & v ) const override { v.visit( this ); }
 	virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
-	DeclarationNode::Aggregate kind;
-  private:
-	virtual std::string typeString() const override;
+	Aggregate kind;
+  private:
+	virtual const char * typeString() const override;
 };
 
@@ -324,5 +326,5 @@
 	virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
   private:
-	virtual std::string typeString() const override;
+	virtual const char * typeString() const override;
 };
 
@@ -341,5 +343,5 @@
   private:
 	std::unordered_map< std::string, long long int > enumValues;
-	virtual std::string typeString() const override;
+	virtual const char * typeString() const override;
 };
 
@@ -357,5 +359,5 @@
 	virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
   private:
-	virtual std::string typeString() const override;
+	virtual const char * typeString() const override;
 };
 
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SynTree/Expression.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Thr Aug 15 13:43:00 2019
-// Update Count     : 64
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 07:55:15 2019
+// Update Count     : 70
 //
 
@@ -22,5 +22,4 @@
 
 #include "Common/utility.h"          // for maybeClone, cloneAll, deleteAll
-#include "Declaration.h"             // for ObjectDecl, DeclarationWithType
 #include "Expression.h"              // for Expression, ImplicitCopyCtorExpr
 #include "InitTweak/InitTweak.h"     // for getCallArg, getPointerBase
@@ -294,5 +293,5 @@
 }
 
-KeywordCastExpr::KeywordCastExpr( Expression * arg, Target target ) : Expression(), arg(arg), target( target ) {
+KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {
 }
 
@@ -304,13 +303,6 @@
 }
 
-const std::string & KeywordCastExpr::targetString() const {
-	static const std::string targetStrs[] = {
-		"coroutine", "thread", "monitor"
-	};
-	static_assert(
-		(sizeof(targetStrs) / sizeof(targetStrs[0])) == ((unsigned long)NUMBER_OF_TARGETS),
-		"Each KeywordCastExpr::Target should have a corresponding string representation"
-	);
-	return targetStrs[(unsigned long)target];
+const char * KeywordCastExpr::targetString() const {
+	return AggregateDecl::aggrString( target );
 }
 
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SynTree/Expression.h	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Thr Aug 15 13:46:00 2019
-// Update Count     : 54
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 16:50:19 2019
+// Update Count     : 60
 //
 
@@ -28,4 +28,5 @@
 #include "Label.h"                // for Label
 #include "Mutator.h"              // for Mutator
+#include "Declaration.h"          // for Aggregate
 #include "SynTree.h"              // for UniqueId
 #include "Visitor.h"              // for Visitor
@@ -229,19 +230,16 @@
 public:
 	Expression * arg;
-	enum Target {
-		Coroutine, Thread, Monitor, NUMBER_OF_TARGETS
-	};
 	struct Concrete {
 		std::string field;
 		std::string getter;
 	};
-	Target target;
+	AggregateDecl::Aggregate target;
 	Concrete concrete_target;
 
-	KeywordCastExpr( Expression * arg, Target target );
+	KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target );
 	KeywordCastExpr( const KeywordCastExpr & other );
 	virtual ~KeywordCastExpr();
 
-	const std::string & targetString() const;
+	const char * targetString() const;
 
 	virtual KeywordCastExpr * clone() const override { return new KeywordCastExpr( * this ); }
Index: src/SynTree/FunctionDecl.cc
===================================================================
--- src/SynTree/FunctionDecl.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SynTree/FunctionDecl.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Mar 16 08:33:41 2017
-// Update Count     : 74
+// Last Modified On : Sat Dec  7 17:40:09 2019
+// Update Count     : 75
 //
 
@@ -23,4 +23,5 @@
 #include "Common/utility.h"      // for maybeClone, printAll
 #include "Declaration.h"         // for FunctionDecl, FunctionDecl::Parent
+#include "Expression.h"
 #include "Parser/LinkageSpec.h"  // for Spec, linkageName, Cforall
 #include "Statement.h"           // for CompoundStmt
Index: src/SynTree/NamedTypeDecl.cc
===================================================================
--- src/SynTree/NamedTypeDecl.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SynTree/NamedTypeDecl.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Aug  9 13:28:00 2017
-// Update Count     : 14
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 08:26:17 2019
+// Update Count     : 15
 //
 
@@ -78,5 +78,5 @@
 }
 
-std::string TypedefDecl::typeString() const { return "typedef"; }
+const char * TypedefDecl::typeString() const { return "typedef"; }
 
 // Local Variables: //
Index: src/SynTree/TypeDecl.cc
===================================================================
--- src/SynTree/TypeDecl.cc	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ src/SynTree/TypeDecl.cc	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Aug  9 14:35:00 2017
-// Update Count     : 6
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Dec 11 17:56:30 2019
+// Update Count     : 10
 //
 
@@ -18,4 +18,5 @@
 
 #include "Common/utility.h"  // for maybeClone
+#include "Parser/ParseNode.h"
 #include "Declaration.h"     // for TypeDecl, TypeDecl::Data, TypeDecl::Kind...
 #include "Type.h"            // for Type, Type::StorageClasses
@@ -31,13 +32,13 @@
 }
 
-std::string TypeDecl::typeString() const {
-	static const std::string kindNames[] = { "object type", "function type", "tuple type" };
+const char * TypeDecl::typeString() const {
+	static const char * kindNames[] = { "sized object type", "sized function type", "sized tuple type" };
 	assertf( sizeof(kindNames)/sizeof(kindNames[0]) == DeclarationNode::NoTypeClass-1, "typeString: kindNames is out of sync." );
 	assertf( kind < sizeof(kindNames)/sizeof(kindNames[0]), "TypeDecl's kind is out of bounds." );
-	return (isComplete() ? "sized " : "") + kindNames[ kind ];
+	return isComplete() ? kindNames[ kind ] : &kindNames[ kind ][ sizeof("sized") ]; // sizeof includes '\0'
 }
 
-std::string TypeDecl::genTypeString() const {
-	static const std::string kindNames[] = { "dtype", "ftype", "ttype" };
+const char * TypeDecl::genTypeString() const {
+	static const char * kindNames[] = { "dtype", "ftype", "ttype" };
 	assertf( sizeof(kindNames)/sizeof(kindNames[0]) == DeclarationNode::NoTypeClass-1, "genTypeString: kindNames is out of sync." );
 	assertf( kind < sizeof(kindNames)/sizeof(kindNames[0]), "TypeDecl's kind is out of bounds." );
Index: tests/.expect/loopctrl.txt
===================================================================
--- tests/.expect/loopctrl.txt	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ tests/.expect/loopctrl.txt	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -6,4 +6,5 @@
 A
 A A A A A A A A A A
+A A A A A A A A A A A
 B B B B B
 C C C C C
@@ -12,4 +13,5 @@
 
 0 1 2 3 4 5 6 7 8 9
+0 1 2 3 4 5 6 7 8 9 10
 1 3 5 7 9
 10 8 6 4 2
@@ -28,4 +30,5 @@
 N N N N N N N N N N
 0 1 2 3 4 5 6 7 8 9
+0 1 2 3 4 5 6 7 8 9 10
 10 9 8 7 6 5 4 3 2 1
 
Index: tests/concurrent/.expect/keywordErrors.txt
===================================================================
--- tests/concurrent/.expect/keywordErrors.txt	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ tests/concurrent/.expect/keywordErrors.txt	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -1,6 +1,6 @@
 concurrent/keywordErrors.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
-struct A: with body 1
+thread A: with body 1
 
 concurrent/keywordErrors.cfa:6:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
-struct B: with body 1
+thread B: with body 1
 
Index: tests/loopctrl.cfa
===================================================================
--- tests/loopctrl.cfa	(revision ae09808982826f9762dcb49b7658c22d1767683a)
+++ tests/loopctrl.cfa	(revision 0f4527d32d53d21910b8e284fd89ad88a2f6ca18)
@@ -10,6 +10,6 @@
 // Created On       : Wed Aug  8 18:32:59 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul 12 12:05:05 2019
-// Update Count     : 106
+// Last Modified On : Thu Dec 12 17:55:26 2019
+// Update Count     : 108
 // 
 
@@ -43,4 +43,5 @@
 	for ( 1 ) { sout | "A"; }							sout | nl;
 	for ( 10 ) { sout | "A"; }							sout | nl;
+	for ( = 10 ) { sout | "A"; }						sout | nl;
 	for ( 1 ~= 10 ~ 2 ) { sout | "B"; }					sout | nl;
 	for ( 10 -~= 1 ~ 2 ) { sout | "C"; }				sout | nl;
@@ -49,4 +50,5 @@
 
 	for ( i; 10 ) { sout | i; }							sout | nl;
+	for ( i; = 10 ) { sout | i; }						sout | nl;
 	for ( i; 1 ~= 10 ~ 2 ) { sout | i; }				sout | nl;
 	for ( i; 10 -~= 1 ~ 2 ) { sout | i; }				sout | nl;
@@ -87,4 +89,5 @@
 	for ( N ) { sout | "N"; }							sout | nl;
 	for ( i; N ) { sout | i; }							sout | nl;
+	for ( i; = N ) { sout | i; }						sout | nl;
 	for ( i; N -~ 0 ) { sout | i; }						sout | nl | nl;
 
