Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 665f43269c6958cbb65487dbaac9e440b9cd5815)
+++ src/AST/Convert.cpp	(revision 312029a731fd1bf1cdd24d3e1d75abf51eb09d71)
@@ -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 665f43269c6958cbb65487dbaac9e440b9cd5815)
+++ src/AST/Decl.cpp	(revision 312029a731fd1bf1cdd24d3e1d75abf51eb09d71)
@@ -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 665f43269c6958cbb65487dbaac9e440b9cd5815)
+++ src/AST/Decl.hpp	(revision 312029a731fd1bf1cdd24d3e1d75abf51eb09d71)
@@ -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 665f43269c6958cbb65487dbaac9e440b9cd5815)
+++ src/AST/Expr.cpp	(revision 312029a731fd1bf1cdd24d3e1d75abf51eb09d71)
@@ -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 665f43269c6958cbb65487dbaac9e440b9cd5815)
+++ src/AST/Expr.hpp	(revision 312029a731fd1bf1cdd24d3e1d75abf51eb09d71)
@@ -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 ); }
