Index: src/AST/Bitfield.hpp
===================================================================
--- src/AST/Bitfield.hpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/Bitfield.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -19,5 +19,5 @@
 
 /// Make a type a bitfield.
-/// Include in type definition to add operators. Used to simulate inheritance because union 
+/// Include in type definition to add operators. Used to simulate inheritance because union
 /// does not allow it. Requires type to have `unsigned val` field
 /// @param BFType  Name of containing type
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/Decl.cpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -14,12 +14,15 @@
 //
 
+#include <cassert>        // for assert, strict_dynamic_cast
 #include <unordered_map>
 
 #include "Decl.hpp"
 
-#include "Fwd.hpp"   // for UniqueId
-#include "Node.hpp"  // for readonly
+#include "Fwd.hpp"        // for UniqueId
+#include "Init.hpp"
+#include "Node.hpp"       // for readonly
 
 namespace ast {
+
 // To canonicalize declarations
 static UniqueId lastUniqueId = 0;
@@ -39,4 +42,37 @@
 	return {};
 }
+
+// --- EnumDecl
+
+bool EnumDecl::valueOf( Decl* enumerator, long long& value ) const {
+	if ( enumValues.empty() ) {
+		long long crntVal = 0;
+		for ( const Decl* member : members ) {
+			const ObjectDecl* field = strict_dynamic_cast< const ObjectDecl* >( member );
+			if ( field->init ) {
+				const SingleInit* init = strict_dynamic_cast< const SingleInit* >( field->init );
+				auto result = eval( init->value );
+				if ( ! result.second ) {
+					SemanticError( init->location, toString( "Non-constexpr in initialization of "
+						"enumerator: ", field ) );
+				}
+				crntVal = result.first;
+			}
+			if ( enumValues.count( field->name ) != 0 ) {
+				SemanticError( location, toString( "Enum ", name, " has multiple members with the " 	"name ", field->name ) );
+			}
+			enumValues[ field->name ] = crntVal;
+			++crntVal;
+		}
+	}
+
+	auto it = enumValues.find( enumerator->name );
+	if ( it != enumValues.end() ) {
+		value = it->second;
+		return true;
+	}
+	return false;
+}
+
 }
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/Decl.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -16,7 +16,9 @@
 #pragma once
 
-#include <string>
+#include <string>              // for string, to_string
+#include <unordered_map>
 #include <vector>
 
+#include "FunctionSpec.hpp"
 #include "Fwd.hpp"             // for UniqueId
 #include "LinkageSpec.hpp"
@@ -24,9 +26,14 @@
 #include "ParseNode.hpp"
 #include "StorageClasses.hpp"
+#include "Type.hpp"            // for Type, ptr<Type>
 #include "Visitor.hpp"
+#include "Parser/ParseNode.h"  // for DeclarationNode::Aggregate
 
 namespace ast {
+
 class Attribute;
 class Expr;
+class Init;
+class TypeDecl;
 
 /// Base declaration class
@@ -39,5 +46,5 @@
 	bool extension = false;
 
-	Decl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 
+	Decl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
 		Linkage::Spec linkage )
 	: ParseNode( loc ), name( name ), storage( storage ), linkage( linkage ) {}
@@ -61,17 +68,139 @@
 	/// This field is generated by SymTab::Validate::Pass2
 	std::string mangleName;
-	/// Stores the scope level at which the variable was declared. 
+	/// Stores the scope level at which the variable was declared.
 	/// Used to access shadowed identifiers.
 	int scopeLevel = 0;
 
 	std::vector<ptr<Attribute>> attributes;
-	Function::Specs funcSpecs;
+	Function::Specs funcSpec;
 	ptr<Expr> asmName;
 	bool isDeleted = false;
 
-	DeclWithType( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 
+	DeclWithType( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
 		Linkage::Spec linkage, std::vector<ptr<Attribute>>&& attrs, Function::Specs fs )
-	: Decl( loc, name, storage, linkage ), mangleName(), attributes( std::move(attrs) ), 
-		funcSpecs(fs), asmName() {}
+	: Decl( loc, name, storage, linkage ), mangleName(), attributes( std::move(attrs) ),
+		funcSpec(fs), asmName() {}
+
+	std::string scopedMangleName() const { return mangleName + "_" + std::to_string(scopeLevel); }
+
+	/// Get type of this declaration. May be generated by subclass
+	virtual const Type* get_type() const = 0;
+	/// Set type of this declaration. May be verified by subclass
+	virtual void set_type(Type*) = 0;
+
+	virtual DeclWithType* accept( Visitor& v ) override = 0;
+private:
+	virtual DeclWithType* clone() const override = 0;
+};
+
+/// Object declaration `Foo foo = 42;`
+class ObjectDecl final : public DeclWithType {
+public:
+	ptr<Type> type;
+	ptr<Init> init;
+	ptr<Expr> bitfieldWidth;
+
+	ObjectDecl( const CodeLocation& loc, const std::string& name, Type* type, Init* init = nullptr,
+		Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, Expr* bitWd = nullptr,
+		std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
+	: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ),
+	  init( init ), bitfieldWidth( bitWd ) {}
+
+	const Type* get_type() const override { return type; }
+	void set_type( Type* ty ) override { type = ty; }
+
+	DeclWithType* accept( Visitor& v ) override { return v.visit( this ); }
+private:
+	ObjectDecl* clone() const override { return new ObjectDecl{ *this }; }
+};
+
+/// Aggregate type declaration base class
+class AggregateDecl : public Decl {
+public:
+	std::vector<ptr<Decl>> members;
+	std::vector<ptr<TypeDecl>> parameters;
+	std::vector<ptr<Attribute>> attributes;
+	bool body = false;
+	readonly<AggregateDecl> parent = {};
+
+	AggregateDecl( const CodeLocation& loc, const std::string& name,
+		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall )
+	: Decl( loc, name, Storage::Classes{}, linkage ), members(), parameters(),
+	  attributes( std::move(attrs) ) {}
+
+	AggregateDecl* set_body( bool b ) { body = b; return this; }
+
+protected:
+	/// Produces a name for the kind of aggregate
+	virtual std::string typeString() const = 0;
+};
+
+/// struct declaration `struct Foo { ... };`
+class StructDecl final : public AggregateDecl {
+public:
+	DeclarationNode::Aggregate kind;
+
+	StructDecl( const CodeLocation& loc, const std::string& name,
+		DeclarationNode::Aggregate kind = DeclarationNode::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; }
+
+	Decl* accept( Visitor& v ) override { return v.visit( this ); }
+private:
+	StructDecl* clone() const override { return new StructDecl{ *this }; }
+
+	std::string typeString() const override { return "struct"; }
+};
+
+/// union declaration `union Foo { ... };`
+class UnionDecl final : public AggregateDecl {
+public:
+	UnionDecl( const CodeLocation& loc, const std::string& name,
+		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall )
+	: AggregateDecl( loc, name, std::move(attrs), linkage ) {}
+
+	Decl* accept( Visitor& v ) override { return v.visit( this ); }
+private:
+	UnionDecl* clone() const override { return new UnionDecl{ *this }; }
+
+	std::string typeString() const override { return "union"; }
+};
+
+/// enum declaration `enum Foo { ... };`
+class EnumDecl final : public AggregateDecl {
+public:
+	EnumDecl( const CodeLocation& loc, const std::string& name,
+		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall )
+	: AggregateDecl( loc, name, std::move(attrs), linkage ), enumValues() {}
+
+	/// gets the integer value for this enumerator, returning true iff value found
+	bool valueOf( Decl* enumerator, long long& value ) const;
+
+	Decl* accept( Visitor& v ) override { return v.visit( this ); }
+private:
+	EnumDecl* clone() const override { return new EnumDecl{ *this }; }
+
+	std::string typeString() const override { return "enum"; }
+
+	/// Map from names to enumerator values; kept private for lazy initialization
+	mutable std::unordered_map< std::string, long long > enumValues;
+};
+
+/// trait declaration `trait Foo( ... ) { ... };`
+class TraitDecl final : public AggregateDecl {
+public:
+	TraitDecl( const CodeLocation& loc, const std::string& name,
+		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall )
+	: AggregateDecl( loc, name, std::move(attrs), linkage ) {}
+
+	Decl* accept( Visitor& v ) override { return v.visit( this ); }
+private:
+	TraitDecl* clone() const override { return new TraitDecl{ *this }; }
+
+	std::string typeString() const override { return "trait"; }
 };
 
Index: src/AST/FunctionSpec.hpp
===================================================================
--- src/AST/FunctionSpec.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
+++ src/AST/FunctionSpec.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -0,0 +1,52 @@
+//
+// 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.
+//
+// FunctionSpec.hpp --
+//
+// 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
+//
+
+#pragma once
+
+#include "Bitfield.hpp"
+
+namespace ast {
+
+namespace Function {
+
+	/// Bitflags for function specifiers
+	enum {
+		Inline   = 1 << 0,
+		Noreturn = 1 << 1,
+		Fortran  = 1 << 2,
+		NumSpecs      = 3
+	};
+
+	/// Bitflag type for storage classes
+	union Specs {
+		unsigned int val;
+		struct {
+			bool is_inline   : 1;
+			bool is_noreturn : 1;
+			bool is_fortran  : 1;
+		};
+
+		MakeBitfield( Specs )
+		MakeBitfieldPrint( NumSpecs )
+	};
+
+}
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Label.hpp
===================================================================
--- src/AST/Label.hpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/Label.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -34,5 +34,5 @@
 		std::vector< ptr<Attribute> > attributes;
 
-		Label( CodeLocation loc, const std::string& name = "", 
+		Label( CodeLocation loc, const std::string& name = "",
 			const std::vector<ptr<Attribute>>& attrs = std::vector<ptr<Attribute>>{} )
 		: location( loc ), name( name ), attributes( attrs ) {}
@@ -47,5 +47,5 @@
 
 	inline std::ostream& operator<< ( std::ostream& out, const Label& l ) { return out << l.name; }
-	
+
 }
 
Index: src/AST/LinkageSpec.cpp
===================================================================
--- src/AST/LinkageSpec.cpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/LinkageSpec.cpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -24,34 +24,37 @@
 
 namespace ast {
-	namespace Linkage {
-		Spec update( CodeLocation loc, Spec spec, const std::string * cmd ) {
-			assert( cmd );
-			std::unique_ptr<const std::string> guard( cmd ); // allocated by lexer
-			if ( *cmd == "\"Cforall\"" ) {
-				spec.is_mangled = true;
-				return spec;
-			} else if ( *cmd == "\"C\"" ) {
-				spec.is_mangled = false;
-				return spec;
-			} else {
-				SemanticError( loc, "Invalid linkage specifier " + *cmd );
-			}
+
+namespace Linkage {
+
+	Spec update( CodeLocation loc, Spec spec, const std::string * cmd ) {
+		assert( cmd );
+		std::unique_ptr<const std::string> guard( cmd ); // allocated by lexer
+		if ( *cmd == "\"Cforall\"" ) {
+			spec.is_mangled = true;
+			return spec;
+		} else if ( *cmd == "\"C\"" ) {
+			spec.is_mangled = false;
+			return spec;
+		} else {
+			SemanticError( loc, "Invalid linkage specifier " + *cmd );
 		}
-	
+	}
 
-		std::string name( Spec spec ) {
-			switch ( spec ) {
-			case Intrinsic:  return "intrinsic";
-			case C:          return "C";
-			case Cforall:    return "Cforall";
-			case AutoGen:    return "autogenerated cfa";
-			case Compiler:   return "compiler built-in";
-			case BuiltinCFA: return "cfa built-in";
-			case BuiltinC:   return "c built-in";
-			default:         return "<unnamed linkage spec>";
-			}
+
+	std::string name( Spec spec ) {
+		switch ( spec ) {
+		case Intrinsic:  return "intrinsic";
+		case C:          return "C";
+		case Cforall:    return "Cforall";
+		case AutoGen:    return "autogenerated cfa";
+		case Compiler:   return "compiler built-in";
+		case BuiltinCFA: return "cfa built-in";
+		case BuiltinC:   return "c built-in";
+		default:         return "<unnamed linkage spec>";
 		}
+	}
 
-	}
+}
+
 }
 
Index: src/AST/LinkageSpec.hpp
===================================================================
--- src/AST/LinkageSpec.hpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/LinkageSpec.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -23,53 +23,54 @@
 namespace ast {
 
-	namespace Linkage {
+namespace Linkage {
 
-		/// Bitflags for linkage specifiers
-		enum {
-			Mangle       = 1 << 0,
-			Generate     = 1 << 1,
-			Overrideable = 1 << 2,
-			Builtin      = 1 << 3,
-			GccBuiltin   = 1 << 4
+	/// Bitflags for linkage specifiers
+	enum {
+		Mangle       = 1 << 0,
+		Generate     = 1 << 1,
+		Overrideable = 1 << 2,
+		Builtin      = 1 << 3,
+		GccBuiltin   = 1 << 4
+	};
+
+	/// Bitflag type for storage classes
+	union Spec {
+		unsigned int val;
+		struct {
+			bool is_mangled      : 1;
+			bool is_generatable  : 1;
+			bool is_overrideable : 1;
+			bool is_builtin      : 1;
+			bool is_gcc_builtin  : 1;
 		};
 
-		/// Bitflag type for storage classes
-		union Spec {
-			unsigned int val;
-			struct {
-				bool is_mangled      : 1;
-				bool is_generatable  : 1;
-				bool is_overrideable : 1;
-				bool is_builtin      : 1;
-				bool is_gcc_builtin  : 1;
-			};
+		MakeBitfield( Spec )
+	};
 
-			MakeBitfield( Spec )
-		};
+	/// If `cmd` = "C" returns `spec` with `is_mangled = false`.
+	/// If `cmd` = "Cforall" returns `spec` with `is_mangled = true`.
+	Spec update( CodeLocation loc, Spec spec, const std::string * cmd );
 
-		/// If `cmd` = "C" returns `spec` with `is_mangled = false`.
-		/// If `cmd` = "Cforall" returns `spec` with `is_mangled = true`. 
-		Spec update( CodeLocation loc, Spec spec, const std::string * cmd );
+	/// A human-readable name for this spec
+	std::string name( Spec spec );
 
-		/// A human-readable name for this spec
-		std::string name( Spec spec );
+	// Pre-defined flag combinations
 
-		// Pre-defined flag combinations
-		
-		/// C built-in defined in prelude
-		constexpr Spec Intrinsic  = { Mangle | Generate | Overrideable | Builtin };
-		/// Ordinary Cforall
-		constexpr Spec Cforall    = { Mangle | Generate };
-		/// C code: not overloadable, not mangled
-		constexpr Spec C          = { Generate };
-		/// Built by translator (e.g. struct assignment)
-		constexpr Spec AutoGen    = { Mangle | Generate | Overrideable };
-		/// GCC internal
-		constexpr Spec Compiler   = { Mangle | Builtin | GccBuiltin };
-		/// Mangled builtins
-		constexpr Spec BuiltinCFA = { Mangle | Generate | Builtin };
-		/// Non-mangled builtins
-		constexpr Spec BuiltinC   = { Generate | Builtin };
-	}
+	/// C built-in defined in prelude
+	constexpr Spec Intrinsic  = { Mangle | Generate | Overrideable | Builtin };
+	/// Ordinary Cforall
+	constexpr Spec Cforall    = { Mangle | Generate };
+	/// C code: not overloadable, not mangled
+	constexpr Spec C          = { Generate };
+	/// Built by translator (e.g. struct assignment)
+	constexpr Spec AutoGen    = { Mangle | Generate | Overrideable };
+	/// GCC internal
+	constexpr Spec Compiler   = { Mangle | Builtin | GccBuiltin };
+	/// Mangled builtins
+	constexpr Spec BuiltinCFA = { Mangle | Generate | Builtin };
+	/// Non-mangled builtins
+	constexpr Spec BuiltinC   = { Generate | Builtin };
+}
+
 }
 
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/Node.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -27,5 +27,5 @@
 class Node {
 public:
-	// override defaults to ensure assignment doesn't 
+	// override defaults to ensure assignment doesn't
 	// change/share reference counts
 	Node() = default;
Index: src/AST/ParseNode.hpp
===================================================================
--- src/AST/ParseNode.hpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/ParseNode.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -28,5 +28,5 @@
 
 		// Default constructor is deliberately omitted, all ParseNodes must have a location.
-		// Escape hatch if needed is to explicitly pass a default-constructed location, but 
+		// Escape hatch if needed is to explicitly pass a default-constructed location, but
 		// this should be used sparingly.
 
Index: src/AST/StorageClasses.hpp
===================================================================
--- src/AST/StorageClasses.hpp	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/StorageClasses.hpp	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -20,32 +20,32 @@
 namespace ast {
 
-	namespace Storage {
+namespace Storage {
 
-		/// Bitflags for storage classes
-		enum {
-			Extern      = 1 << 0,
-			Static      = 1 << 1,
-			Auto        = 1 << 2,
-			Register    = 1 << 3,
-			ThreadLocal = 1 << 4,
-			NumClasses       = 5
+	/// Bitflags for storage classes
+	enum {
+		Extern      = 1 << 0,
+		Static      = 1 << 1,
+		Auto        = 1 << 2,
+		Register    = 1 << 3,
+		ThreadLocal = 1 << 4,
+		NumClasses       = 5
+	};
+
+	/// Bitflag type for storage classes
+	union Classes {
+		unsigned int val;
+		struct {
+			bool is_extern      : 1;
+			bool is_static      : 1;
+			bool is_auto        : 1;
+			bool is_register    : 1;
+			bool is_threadlocal : 1;
 		};
 
-		/// Bitflag type for storage classes
-		union Classes {
-			unsigned int val;
-			struct {
-				bool is_extern      : 1;
-				bool is_static      : 1;
-				bool is_auto        : 1;
-				bool is_register    : 1;
-				bool is_threadlocal : 1;
-			};
+		MakeBitfield( Classes )
+		MakeBitfieldPrint( NumClasses )
+	};
 
-			MakeBitfield( Classes )
-			MakeBitfieldPrint( NumClasses )
-		};
-
-	}
+}
 }
 
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision 292d599b65d54a5005b8bf8c6e8d95e4a5761fb8)
+++ src/AST/porting.md	(revision cdcd53dca689985e90e65039a76777261b54c5ea)
@@ -55,9 +55,9 @@
 * Preserve names from previous AST whenever reasonable, and get team consensus on any changes.
 * Strong justification required for private fields
-  * No `get_` prefix on getters
+  * No `get_` prefix on getters (including for generated fields)
 * Notable changes:
   * for concision and consistency with subclasses:
     * `Declaration` => `ast::Decl`
-	* `DeclarationWithType` => `ast::DeclWithType`  
+	* `DeclarationWithType` => `ast::DeclWithType`
 	* `Expression` => `ast::Expr`
 	* `Initializer` => `ast::Init`
@@ -81,4 +81,14 @@
 `DeclWithType`
 * When `SymTab::Validate::Pass2` is rewritten, update comment on `mangleName` with new name of pass
+* `get_scopedMangleName()` => `scopedMangleName()`
+* `get_type()` now returns `const Type*` so can't be inadvertently mutated
+  * still with `get_` name so it doesn't conflict with subclass field names
+
+`ObjectDecl`
+* changed constructor parameter order for better defaults
+  * allows `newObject` as just default settings
+
+`EnumDecl`
+* **TODO** rebuild `eval` for new AST (re: `valueOf` implementation)
 
 `Expr`
