Index: src/CodeGen/CodeGenerator.cpp
===================================================================
--- src/CodeGen/CodeGenerator.cpp	(revision df78cce298234f5393935a7b378e26335eaf33ff)
+++ src/CodeGen/CodeGenerator.cpp	(revision 486caad7c0e53d562d8675ebf6836c087eaa427b)
@@ -192,10 +192,13 @@
 	}
 
-	assert( decl->returns.size() < 2 );
 	if ( 1 == decl->returns.size() ) {
 		ast::ptr<ast::Type> const & type = decl->returns[0]->get_type();
 		output << genTypeNoAttr( type, acc.str(), subOptions );
-	} else {
+	} else if ( 0 == decl->returns.size() ) {
 		output << "void " + acc.str();
+	} else {
+		assertf( !options.genC, "Multi-return should not reach code generation." );
+		ast::ptr<ast::Type> type = new ast::TupleType( copy( decl->type->returns ) );
+		output << genTypeNoAttr( type, acc.str(), subOptions );
 	}
 
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision df78cce298234f5393935a7b378e26335eaf33ff)
+++ src/Parser/DeclarationNode.cc	(revision 486caad7c0e53d562d8675ebf6836c087eaa427b)
@@ -185,6 +185,4 @@
 	newnode->type->aggregate.fields = fields;
 	newnode->type->aggregate.body = body;
-	newnode->type->aggregate.tagged = false;
-	newnode->type->aggregate.parent = nullptr;
 	return newnode;
 } // DeclarationNode::newAggregate
@@ -199,6 +197,10 @@
 	newnode->type->enumeration.typed = typed;
 	newnode->type->enumeration.hiding = hiding;
-	if ( base && base->type )  {
+	if ( base ) {
+		assert( typed );
+		assert( base->type );
 		newnode->type->base = base->type;
+		base->type = nullptr;
+		delete base;
 	} // if
 
@@ -220,14 +222,12 @@
 
 DeclarationNode * DeclarationNode::newEnumValueGeneric( const string * name, InitializerNode * init ) {
-	if ( init ) {
-		if ( init->get_expression() ) {
-			return newEnumConstant( name, init->get_expression() );
-		} else {
-			DeclarationNode * newnode = newName( name );
-			newnode->initializer = init;
-			return newnode;
-		} // if
+	if ( nullptr == init ) {
+		return newName( name );
+	} else if ( init->get_expression() ) {
+		return newEnumConstant( name, init->get_expression() );
 	} else {
-		return newName( name );
+		DeclarationNode * newnode = newName( name );
+		newnode->initializer = init;
+		return newnode;
 	} // if
 } // DeclarationNode::newEnumValueGeneric
@@ -502,4 +502,102 @@
 }
 
+// This code handles a special issue with the attribute transparent_union.
+//
+//    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
+//
+// Here the attribute aligned goes with the typedef_name, so variables declared of this type are
+// aligned.  However, the attribute transparent_union must be moved from the typedef_name to
+// alias union U.  Currently, this is the only know attribute that must be moved from typedef to
+// alias.
+static void moveUnionAttribute( DeclarationNode * decl, DeclarationNode * unionDecl ) {
+	assert( decl->type->kind == TypeData::Symbolic );
+	assert( decl->type->symbolic.isTypedef );
+	assert( unionDecl->type->kind == TypeData::Aggregate );
+
+	if ( unionDecl->type->aggregate.kind != ast::AggregateDecl::Union ) return;
+
+	// Ignore the Aggregate_t::attributes. Why did we add that before the rework?
+	for ( auto attr = decl->attributes.begin() ; attr != decl->attributes.end() ; ) {
+		if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
+			unionDecl->attributes.emplace_back( attr->release() );
+			attr = decl->attributes.erase( attr );
+		} else {
+			++attr;
+		}
+	}
+}
+
+// Helper for addTypedef, handles the case where the typedef wraps an
+// aggregate declaration (not a type), returns a chain of nodes.
+static DeclarationNode * addTypedefAggr(
+		DeclarationNode * olddecl, TypeData * newtype ) {
+	TypeData *& oldaggr = olddecl->type->aggInst.aggregate;
+
+	// Handle anonymous aggregates: typedef struct { int i; } foo
+	// Give the typedefed type a consistent name across translation units.
+	if ( oldaggr->aggregate.anon ) {
+		delete oldaggr->aggregate.name;
+		oldaggr->aggregate.name = new string( "__anonymous_" + *olddecl->name );
+		oldaggr->aggregate.anon = false;
+		oldaggr->qualifiers.reset();
+	}
+
+	// Replace the wrapped TypeData with a forward declaration.
+	TypeData * newaggr = new TypeData( TypeData::Aggregate );
+	newaggr->aggregate.kind = oldaggr->aggregate.kind;
+	newaggr->aggregate.name = oldaggr->aggregate.name ? new string( *oldaggr->aggregate.name ) : nullptr;
+	newaggr->aggregate.body = false;
+	newaggr->aggregate.anon = oldaggr->aggregate.anon;
+	swap( newaggr, oldaggr );
+
+	newtype->base = olddecl->type;
+	olddecl->type = newtype;
+	DeclarationNode * newdecl = new DeclarationNode;
+	newdecl->type = newaggr;
+	newdecl->next = olddecl;
+
+	moveUnionAttribute( olddecl, newdecl );
+
+	return newdecl;
+}
+
+// Helper for addTypedef, handles the case where the typedef wraps an
+// enumeration declaration (not a type), returns a chain of nodes.
+static DeclarationNode * addTypedefEnum(
+		DeclarationNode * olddecl, TypeData * newtype ) {
+	TypeData *& oldenum = olddecl->type->aggInst.aggregate;
+
+	// Handle anonymous enumeration: typedef enum { A, B, C } foo
+	// Give the typedefed type a consistent name across translation units.
+	if ( oldenum->enumeration.anon ) {
+		delete oldenum->enumeration.name;
+		oldenum->enumeration.name = new string( "__anonymous_" + *olddecl->name );
+		oldenum->enumeration.anon = false;
+		oldenum->qualifiers.reset();
+	}
+
+	// Replace the wrapped TypeData with a forward declaration.
+	TypeData * newenum = new TypeData( TypeData::Enum );
+	newenum->enumeration.name = oldenum->enumeration.name ? new string( *oldenum->enumeration.name ) : nullptr;
+	newenum->enumeration.body = false;
+	newenum->enumeration.anon = oldenum->enumeration.anon;
+	newenum->enumeration.typed = oldenum->enumeration.typed;
+	newenum->enumeration.hiding = oldenum->enumeration.hiding;
+	swap( newenum, oldenum );
+
+	newtype->base = olddecl->type;
+	olddecl->type = newtype;
+	DeclarationNode * newdecl = new DeclarationNode;
+	newdecl->type = newenum;
+	newdecl->next = olddecl;
+
+	return newdecl;
+}
+
+// Wrap the declaration in a typedef. It actually does that by modifying the
+// existing declaration, and may split it into two declarations.
+// This only happens if the wrapped type is actually a declaration of a SUE
+// type. If it does, the DeclarationNode for the SUE declaration is the node
+// returned, make sure later transformations are applied to the right node.
 DeclarationNode * DeclarationNode::addTypedef() {
 	TypeData * newtype = new TypeData( TypeData::Symbolic );
@@ -507,7 +605,20 @@
 	newtype->symbolic.isTypedef = true;
 	newtype->symbolic.name = name ? new string( *name ) : nullptr;
-	newtype->base = type;
-	type = newtype;
-	return this;
+	// If this typedef is wrapping an aggregate, separate them out.
+	if ( TypeData::AggregateInst == type->kind
+			&& TypeData::Aggregate == type->aggInst.aggregate->kind
+			&& type->aggInst.aggregate->aggregate.body ) {
+		return addTypedefAggr( this, newtype );
+	// If this typedef is wrapping an enumeration, separate them out.
+	} else if ( TypeData::AggregateInst == type->kind
+			&& TypeData::Enum == type->aggInst.aggregate->kind
+			&& type->aggInst.aggregate->enumeration.body ) {
+		return addTypedefEnum( this, newtype );
+	// There is no internal declaration, just a type.
+	} else {
+		newtype->base = type;
+		type = newtype;
+		return this;
+	}
 }
 
@@ -711,73 +822,4 @@
 }
 
-// If a typedef wraps an anonymous declaration, name the inner declaration so it has a consistent name across
-// translation units.
-static void nameTypedefedDecl(
-		DeclarationNode * innerDecl,
-		const DeclarationNode * outerDecl ) {
-	TypeData * outer = outerDecl->type;
-	assert( outer );
-	// First make sure this is a typedef:
-	if ( outer->kind != TypeData::Symbolic || !outer->symbolic.isTypedef ) {
-		return;
-	}
-	TypeData * inner = innerDecl->type;
-	assert( inner );
-	// Always clear any CVs associated with the aggregate:
-	inner->qualifiers.reset();
-	// Handle anonymous aggregates: typedef struct { int i; } foo
-	if ( inner->kind == TypeData::Aggregate && inner->aggregate.anon ) {
-		delete inner->aggregate.name;
-		inner->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
-		inner->aggregate.anon = false;
-		assert( outer->base );
-		delete outer->base->aggInst.aggregate->aggregate.name;
-		outer->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
-		outer->base->aggInst.aggregate->aggregate.anon = false;
-		outer->base->aggInst.aggregate->qualifiers.reset();
-	// Handle anonymous enumeration: typedef enum { A, B, C } foo
-	} else if ( inner->kind == TypeData::Enum && inner->enumeration.anon ) {
-		delete inner->enumeration.name;
-		inner->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
-		inner->enumeration.anon = false;
-		assert( outer->base );
-		delete outer->base->aggInst.aggregate->enumeration.name;
-		outer->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
-		outer->base->aggInst.aggregate->enumeration.anon = false;
-		// No qualifiers.reset() here.
-	}
-}
-
-// This code handles a special issue with the attribute transparent_union.
-//
-//    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
-//
-// Here the attribute aligned goes with the typedef_name, so variables declared of this type are
-// aligned.  However, the attribute transparent_union must be moved from the typedef_name to
-// alias union U.  Currently, this is the only know attribute that must be moved from typedef to
-// alias.
-static void moveUnionAttribute( ast::Decl * decl, ast::UnionDecl * unionDecl ) {
-	if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) {
-		// Is the typedef alias a union aggregate?
-		if ( nullptr == unionDecl ) return;
-
-		// If typedef is an alias for a union, then its alias type was hoisted above and remembered.
-		if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) {
-			auto instType = ast::mutate( unionInstType );
-			// Remove all transparent_union attributes from typedef and move to alias union.
-			for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) {
-				assert( *attr );
-				if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
-					unionDecl->attributes.emplace_back( attr->release() );
-					attr = instType->attributes.erase( attr );
-				} else {
-					attr++;
-				}
-			}
-			typedefDecl->base = instType;
-		}
-	}
-}
-
 // Get the non-anonymous name of the instance type of the declaration,
 // if one exists.
@@ -800,14 +842,9 @@
 		try {
 			bool extracted_named = false;
-			ast::UnionDecl * unionDecl = nullptr;
 
 			if ( DeclarationNode * extr = cur->extractAggregate() ) {
 				assert( cur->type );
-				nameTypedefedDecl( extr, cur );
 
 				if ( ast::Decl * decl = extr->build() ) {
-					// Remember the declaration if it is a union aggregate ?
-					unionDecl = dynamic_cast<ast::UnionDecl *>( decl );
-
 					*out++ = decl;
 
@@ -828,6 +865,4 @@
 
 			if ( ast::Decl * decl = cur->build() ) {
-				moveUnionAttribute( decl, unionDecl );
-
 				if ( "" == decl->name && !cur->get_inLine() ) {
 					// Don't include anonymous declaration for named aggregates,
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision df78cce298234f5393935a7b378e26335eaf33ff)
+++ src/Parser/TypeData.cc	(revision 486caad7c0e53d562d8675ebf6836c087eaa427b)
@@ -88,6 +88,4 @@
 		aggregate.fields = nullptr;
 		aggregate.body = false;
-		aggregate.tagged = false;
-		aggregate.parent = nullptr;
 		aggregate.anon = false;
 		break;
@@ -221,5 +219,4 @@
 		newtype->aggregate.kind = aggregate.kind;
 		newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
-		newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr;
 		newtype->aggregate.params = maybeCopy( aggregate.params );
 		newtype->aggregate.actuals = maybeCopy( aggregate.actuals );
@@ -228,5 +225,4 @@
 		newtype->aggregate.body = aggregate.body;
 		newtype->aggregate.anon = aggregate.anon;
-		newtype->aggregate.tagged = aggregate.tagged;
 		break;
 	case AggregateInst:
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision df78cce298234f5393935a7b378e26335eaf33ff)
+++ src/Parser/TypeData.h	(revision 486caad7c0e53d562d8675ebf6836c087eaa427b)
@@ -48,5 +48,4 @@
 		ast::AggregateDecl::Aggregate kind;
 		const std::string * name = nullptr;
-		const std::string * parent = nullptr;
 		DeclarationNode * params = nullptr;
 		ExpressionNode * actuals = nullptr;				// holds actual parameters later applied to AggInst
@@ -55,5 +54,4 @@
 		bool body;
 		bool anon;
-		bool tagged;
 	};
 
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision df78cce298234f5393935a7b378e26335eaf33ff)
+++ src/Parser/parser.yy	(revision 486caad7c0e53d562d8675ebf6836c087eaa427b)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Mar 11 18:30:03 2024
-// Update Count     : 6589
+// Last Modified On : Sat Mar 16 18:19:23 2024
+// Update Count     : 6617
 //
 
@@ -485,5 +485,5 @@
 %type<decl> elaborated_type elaborated_type_nobody
 
-%type<decl> enumerator_list enum_type enum_type_nobody
+%type<decl> enumerator_list enum_type enum_type_nobody enumerator_type
 %type<init> enumerator_value_opt
 
@@ -2742,8 +2742,24 @@
 
 enum_type:
-	ENUM attribute_list_opt '{' enumerator_list comma_opt '}'
-		{ $$ = DeclarationNode::newEnum( nullptr, $4, true, false )->addQualifiers( $2 ); }
-	| ENUM attribute_list_opt '!' '{' enumerator_list comma_opt '}'	// invalid syntax rule
-		{ SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
+		// anonymous, no type name 
+	ENUM attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
+		{
+			if ( $3 == EnumHiding::Hide ) {
+				SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr;
+			} // if
+			$$ = DeclarationNode::newEnum( nullptr, $5, true, false )->addQualifiers( $2 );
+		}
+	| ENUM enumerator_type attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
+		{
+			if ( $2 && ($2->storageClasses.val != 0 || $2->type->qualifiers.any()) ) {
+				SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
+			}
+			if ( $4 == EnumHiding::Hide ) {
+				SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr;
+			} // if
+			$$ = DeclarationNode::newEnum( nullptr, $6, true, true, $2 )->addQualifiers( $3 );
+		}
+
+		// named type
 	| ENUM attribute_list_opt identifier
 		{ typedefTable.makeTypedef( *$3, "enum_type 1" ); }
@@ -2752,43 +2768,25 @@
 	| ENUM attribute_list_opt typedef_name hide_opt '{' enumerator_list comma_opt '}' // unqualified type name
 		{ $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); }
-	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
-		{
-			if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() ) {
+	| ENUM enumerator_type attribute_list_opt identifier attribute_list_opt
+		{
+			if ( $2 && ($2->storageClasses.any() || $2->type->qualifiers.val != 0) ) {
 				SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
 			}
-			$$ = DeclarationNode::newEnum( nullptr, $7, true, true, $3 )->addQualifiers( $5 );
-		}
-	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}' // unqualified type name
-		{ SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
-	| ENUM '(' ')' attribute_list_opt '{' enumerator_list comma_opt '}'
-		{
-			$$ = DeclarationNode::newEnum( nullptr, $6, true, true )->addQualifiers( $4 );
-		}
-	| ENUM '(' ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}'	// invalid syntax rule
-		{ SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
-	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
-		{
-			if ( $3 && ($3->storageClasses.any() || $3->type->qualifiers.val != 0) ) {
-				SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
-			}
-			typedefTable.makeTypedef( *$6, "enum_type 2" );
+			typedefTable.makeTypedef( *$4, "enum_type 2" );
 		}
 	  hide_opt '{' enumerator_list comma_opt '}'
-		{
-			$$ = DeclarationNode::newEnum( $6, $11, true, true, $3, $9 )->addQualifiers( $5 )->addQualifiers( $7 );
-		}
-	| ENUM '(' ')' attribute_list_opt identifier attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
-		{
-			$$ = DeclarationNode::newEnum( $5, $9, true, true, nullptr, $7 )->addQualifiers( $4 )->addQualifiers( $6 );
-		}
-	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
-		{
-			$$ = DeclarationNode::newEnum( $6->name, $10, true, true, $3, $8 )->addQualifiers( $5 )->addQualifiers( $7 );
-		}
-	| ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
-		{
-			$$ = DeclarationNode::newEnum( $5->name, $9, true, true, nullptr, $7 )->addQualifiers( $4 )->addQualifiers( $6 );
-		}
+		{ $$ = DeclarationNode::newEnum( $4, $9, true, true, $2, $7 )->addQualifiers( $3 )->addQualifiers( $5 ); }
+	| ENUM enumerator_type attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
+		{ $$ = DeclarationNode::newEnum( $4->name, $8, true, true, $2, $6 )->addQualifiers( $3 )->addQualifiers( $5 ); }
+
+		// forward declaration
 	| enum_type_nobody
+	;
+
+enumerator_type:
+	'(' ')'												// pure enumeration
+		{ $$ = nullptr; }
+	| '(' cfa_abstract_parameter_declaration ')'		// typed enumeration
+		{ $$ = $2; }
 	;
 
Index: src/main.cc
===================================================================
--- src/main.cc	(revision df78cce298234f5393935a7b378e26335eaf33ff)
+++ src/main.cc	(revision 486caad7c0e53d562d8675ebf6836c087eaa427b)
@@ -101,8 +101,4 @@
 }
 
-// Helpers for checkInvariant:
-void checkInvariants( std::list< Declaration * > & ) {}
-using ast::checkInvariants;
-
 #define PASS( name, pass, unit, ... )       \
 	if ( errorp ) { cerr << name << endl; } \
@@ -112,5 +108,5 @@
 	Stats::Time::StopBlock();               \
 	if ( invariant ) {                      \
-		checkInvariants(unit);              \
+		ast::checkInvariants(unit);         \
 	}
 
