Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 2bb4a01b67c9bef5d552f56c14abeca79a2985d2)
+++ src/AST/Decl.hpp	(revision a300e4a85b7745f590bfbef5fc5182df7a469c97)
@@ -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,13 @@
 #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 TypeDecl;
 
 /// Base declaration class
@@ -66,5 +72,5 @@
 
 	std::vector<ptr<Attribute>> attributes;
-	Function::Specs funcSpecs;
+	Function::Specs funcSpec;
 	ptr<Expr> asmName;
 	bool isDeleted = false;
@@ -73,5 +79,106 @@
 		Linkage::Spec linkage, std::vector<ptr<Attribute>>&& attrs, Function::Specs fs )
 	: Decl( loc, name, storage, linkage ), mangleName(), attributes( std::move(attrs) ), 
-		funcSpecs(fs), asmName() {}
+		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* 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;
+};
+
+/// 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"; }
 };
 
