Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision d859a304c3462b4df9c1da7c43844f9ba9c1a3f2)
+++ src/AST/Convert.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -321,4 +321,8 @@
 			get<Type>().accept1(node->base)
 		);
+		decl->data_constructors = get<StructDecl>().acceptL( node->data_constructors );
+		decl->data_union = get<UnionDecl>().accept1( node->data_union );
+		decl->tags = get<EnumDecl>().accept1( node->tag );
+		decl->tag_union = get<StructDecl>().accept1( node->tag_union );
 		return aggregatePostamble( decl, node );
 	}
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision d859a304c3462b4df9c1da7c43844f9ba9c1a3f2)
+++ src/AST/Decl.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -132,5 +132,5 @@
 
 // These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
-static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName" };
+static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName", "data" };
 
 const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision d859a304c3462b4df9c1da7c43844f9ba9c1a3f2)
+++ src/AST/Decl.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -248,5 +248,5 @@
 class AggregateDecl : public Decl {
 public:
-	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate };
+	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate, ADT };
 	static const char * aggrString( Aggregate aggr );
 
@@ -286,4 +286,5 @@
 	bool is_monitor  () const { return kind == Monitor  ; }
 	bool is_thread   () const { return kind == Thread   ; }
+	bool is_adt		 () const { return kind == ADT		; }
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
@@ -320,7 +321,13 @@
 	enum class EnumHiding { Visible, Hide } hide;
 
+	std::vector<ptr<StructDecl>> data_constructors;
+	bool isData = false;
+	ptr<UnionDecl> data_union;
+	ptr<EnumDecl> tag;
+	ptr<StructDecl> tag_union;
+
 	EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false,
 		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall,
-		Type const * base = nullptr, EnumHiding hide = EnumHiding::Hide,
+		Type const * base = nullptr, EnumHiding hide = EnumHiding::Visible,
 		std::unordered_map< std::string, long long > enumValues = std::unordered_map< std::string, long long >() )
 	: AggregateDecl( loc, name, std::move(attrs), linkage ), isTyped(isTyped), base(base), hide(hide), enumValues(enumValues) {}
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision d859a304c3462b4df9c1da7c43844f9ba9c1a3f2)
+++ src/AST/Pass.impl.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
@@ -693,4 +693,8 @@
 			maybe_accept( node, &EnumDecl::members    );
 			maybe_accept( node, &EnumDecl::attributes );
+			maybe_accept( node, &EnumDecl::data_constructors );
+			maybe_accept( node, &EnumDecl::data_union );
+			maybe_accept( node, &EnumDecl::tag );
+			maybe_accept( node, &EnumDecl::tag_union );
 		} else {
 			maybe_accept( node, &EnumDecl::base );
@@ -698,4 +702,8 @@
 			maybe_accept( node, &EnumDecl::members    );
 			maybe_accept( node, &EnumDecl::attributes );
+			maybe_accept( node, &EnumDecl::data_constructors );
+			maybe_accept( node, &EnumDecl::data_union );
+			maybe_accept( node, &EnumDecl::tag );
+			maybe_accept( node, &EnumDecl::tag_union );
 		}
 	}
