Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 589a70bdeb3a95811f5c130296fd64d14e0c6498)
+++ src/SymTab/Validate.cc	(revision 29f9e20c3cabdb3ee724c7e3c4b6cc97003758c9)
@@ -80,11 +80,17 @@
 
 namespace SymTab {
+	struct LinkNestedTypes final : public WithDeclsToAdd {
+		void previsit( AggregateDecl * aggr );
+
+		void previsit( SizeofExpr * );
+		void previsit( AlignofExpr * );
+		void previsit( UntypedOffsetofExpr * );
+		void handleType( Type * );
+	};
+
 	struct HoistStruct final : public WithDeclsToAdd, public WithGuards {
 		/// Flattens nested struct types
 		static void hoistStruct( std::list< Declaration * > &translationUnit );
 
-		void previsit( EnumInstType * enumInstType );
-		void previsit( StructInstType * structInstType );
-		void previsit( UnionInstType * unionInstType );
 		void previsit( StructDecl * aggregateDecl );
 		void previsit( UnionDecl * aggregateDecl );
@@ -263,10 +269,12 @@
 		PassVisitor<FindSpecialDeclarations> finder;
 		PassVisitor<LabelAddressFixer> labelAddrFixer;
-
+		PassVisitor<LinkNestedTypes> nestedTypes;
+
+		acceptAll( translationUnit, nestedTypes );
 		EliminateTypedef::eliminateTypedef( translationUnit );
-		HoistStruct::hoistStruct( translationUnit ); // must happen after EliminateTypedef, so that aggregate typedefs occur in the correct order
 		ReturnTypeFixer::fix( translationUnit ); // must happen before autogen
 		acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes because it is an indexer and needs correct types for mangling
 		acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions
+		HoistStruct::hoistStruct( translationUnit ); // must happen after EliminateTypedef, so that aggregate typedefs occur in the correct order
 		acceptAll( translationUnit, genericParams );  // check as early as possible - can't happen before LinkReferenceToTypes
 		VerifyCtorDtorAssign::verify( translationUnit );  // must happen before autogen, because autogen examines existing ctor/dtors
@@ -294,4 +302,43 @@
 	}
 
+
+	void LinkNestedTypes::previsit( AggregateDecl * aggr ) {
+		for ( auto it = aggr->members.begin(); it != aggr->members.end(); ) {
+			auto current = it++;
+			Declaration * member = *current;
+			if ( AggregateDecl * child = dynamic_cast<AggregateDecl *>( member ) ) {
+				child->parent = aggr;
+			}
+		}
+	}
+
+	void LinkNestedTypes::handleType( Type * type ) {
+		// some type declarations are buried in expressions and not easy to hoist during parsing; hoist them here
+		AggregateDecl * aggr = nullptr;
+		if ( StructInstType * inst = dynamic_cast< StructInstType * >( type ) ) {
+			aggr = inst->baseStruct;
+		} else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( type ) ) {
+			aggr = inst->baseUnion;
+		} else if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( type ) ) {
+			aggr = inst->baseEnum;
+		}
+		if ( aggr && aggr->body ) {
+			declsToAddBefore.push_front( aggr );
+		}
+	}
+
+	void LinkNestedTypes::previsit( SizeofExpr * expr ) {
+		handleType( expr->type );
+	}
+
+	void LinkNestedTypes::previsit( AlignofExpr * expr ) {
+		handleType( expr->type );
+	}
+
+	void LinkNestedTypes::previsit( UntypedOffsetofExpr * expr ) {
+		handleType( expr->type );
+	}
+
+
 	void HoistStruct::hoistStruct( std::list< Declaration * > &translationUnit ) {
 		PassVisitor<HoistStruct> hoister;
@@ -316,22 +363,4 @@
 	}
 
-	void HoistStruct::previsit( EnumInstType * inst ) {
-		if ( inst->baseEnum && inst->baseEnum->body ) {
-			declsToAddBefore.push_front( inst->baseEnum );
-		}
-	}
-
-	void HoistStruct::previsit( StructInstType * inst ) {
-		if ( inst->baseStruct && inst->baseStruct->body ) {
-			declsToAddBefore.push_front( inst->baseStruct );
-		}
-	}
-
-	void HoistStruct::previsit( UnionInstType * inst ) {
-		if ( inst->baseUnion && inst->baseUnion->body ) {
-			declsToAddBefore.push_front( inst->baseUnion );
-		}
-	}
-
 	void HoistStruct::previsit( StaticAssertDecl * assertDecl ) {
 		if ( parentAggr ) {
@@ -398,8 +427,7 @@
 		// it's not a semantic error if the enum is not found, just an implicit forward declaration
 		if ( st ) {
-			//assert( ! enumInst->get_baseEnum() || enumInst->get_baseEnum()->get_members().empty() || ! st->get_members().empty() );
 			enumInst->baseEnum = st;
 		} // if
-		if ( ! st || st->members.empty() ) {
+		if ( ! st || ! st->body ) {
 			// use of forward declaration
 			forwardEnums[ enumInst->name ].push_back( enumInst );
@@ -419,8 +447,7 @@
 		// it's not a semantic error if the struct is not found, just an implicit forward declaration
 		if ( st ) {
-			//assert( ! structInst->get_baseStruct() || structInst->get_baseStruct()->get_members().empty() || ! st->get_members().empty() );
 			structInst->baseStruct = st;
 		} // if
-		if ( ! st || st->members.empty() ) {
+		if ( ! st || ! st->body ) {
 			// use of forward declaration
 			forwardStructs[ structInst->name ].push_back( structInst );
@@ -435,5 +462,5 @@
 			unionInst->baseUnion = un;
 		} // if
-		if ( ! un || un->members.empty() ) {
+		if ( ! un || ! un->body ) {
 			// use of forward declaration
 			forwardUnions[ unionInst->name ].push_back( unionInst );
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision 589a70bdeb3a95811f5c130296fd64d14e0c6498)
+++ src/SynTree/Declaration.h	(revision 29f9e20c3cabdb3ee724c7e3c4b6cc97003758c9)
@@ -266,4 +266,5 @@
 	bool body;
 	std::list< Attribute * > attributes;
+	AggregateDecl * parent = nullptr;
 
 	AggregateDecl( const std::string &name, const std::list< Attribute * > & attributes = std::list< class Attribute * >(), LinkageSpec::Spec linkage = LinkageSpec::Cforall );
