Index: src/GenPoly/InstantiateGeneric.cc
===================================================================
--- src/GenPoly/InstantiateGeneric.cc	(revision cadec252fb976dc6b34a5656cac9e30b1c79ca99)
+++ src/GenPoly/InstantiateGeneric.cc	(revision 3f06c054c29fad4a3749737f921921586777df75)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Thu Aug 04 18:33:00 2016
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Thu Aug 04 18:33:00 2016
-// Update Count     : 1
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jul 16 10:17:00 2020
+// Update Count     : 2
 //
 #include "InstantiateGeneric.h"
@@ -297,4 +297,16 @@
 	}
 
+	template< typename AggrInst >
+	static AggrInst * asForward( AggrInst * decl ) {
+		if ( !decl->body ) {
+			return nullptr;
+		}
+		decl = decl->clone();
+		decl->body = false;
+		deleteAll( decl->members );
+		decl->members.clear();
+		return decl;
+	}
+
 	void GenericInstantiator::stripDtypeParams( AggregateDecl *base, std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs ) {
 		substituteMembers( base->get_members(), baseParams, typeSubs );
@@ -373,5 +385,9 @@
 				concDecl->set_body( inst->get_baseStruct()->has_body() );
 				substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
-				insert( inst, typeSubs, concDecl ); // must insert before recursion
+				// Forward declare before recursion. (TODO: Only when needed, #199.)
+				insert( inst, typeSubs, concDecl );
+				if ( StructDecl *forwardDecl = asForward( concDecl ) ) {
+					declsToAddBefore.push_back( forwardDecl );
+				}
 				concDecl->acceptMutator( *visitor ); // recursively instantiate members
 				declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first
@@ -423,5 +439,9 @@
 				concDecl->set_body( inst->get_baseUnion()->has_body() );
 				substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
-				insert( inst, typeSubs, concDecl ); // must insert before recursion
+				// Forward declare before recursion. (TODO: Only when needed, #199.)
+				insert( inst, typeSubs, concDecl );
+				if ( UnionDecl *forwardDecl = asForward( concDecl ) ) {
+					declsToAddBefore.push_back( forwardDecl );
+				}
 				concDecl->acceptMutator( *visitor ); // recursively instantiate members
 				declsToAddBefore.push_back( concDecl ); // must occur before declaration is added so that member instantiations appear first
Index: tests/.expect/functions.x64.txt
===================================================================
--- tests/.expect/functions.x64.txt	(revision cadec252fb976dc6b34a5656cac9e30b1c79ca99)
+++ tests/.expect/functions.x64.txt	(revision 3f06c054c29fad4a3749737f921921586777df75)
@@ -121,4 +121,5 @@
 
 }
+struct _conc__tuple2_0;
 struct _conc__tuple2_0 {
     signed int field_0;
@@ -157,4 +158,5 @@
 
 }
+struct _conc__tuple3_1;
 struct _conc__tuple3_1 {
     signed int field_0;
@@ -170,4 +172,5 @@
     __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
 }
+struct _conc__tuple3_2;
 struct _conc__tuple3_2 {
     signed int field_0;
@@ -260,4 +263,5 @@
     __attribute__ ((unused)) signed int *const _X10_retval_f3KPi_1;
 }
+struct _conc__tuple2_3;
 struct _conc__tuple2_3 {
     signed int *field_0;
Index: tests/.expect/functions.x86.txt
===================================================================
--- tests/.expect/functions.x86.txt	(revision cadec252fb976dc6b34a5656cac9e30b1c79ca99)
+++ tests/.expect/functions.x86.txt	(revision 3f06c054c29fad4a3749737f921921586777df75)
@@ -121,4 +121,5 @@
 
 }
+struct _conc__tuple2_0;
 struct _conc__tuple2_0 {
     signed int field_0;
@@ -157,4 +158,5 @@
 
 }
+struct _conc__tuple3_1;
 struct _conc__tuple3_1 {
     signed int field_0;
@@ -170,4 +172,5 @@
     __attribute__ ((unused)) struct _conc__tuple3_1 _X9_retval_fT3iii_1 = {  };
 }
+struct _conc__tuple3_2;
 struct _conc__tuple3_2 {
     signed int field_0;
@@ -260,4 +263,5 @@
     __attribute__ ((unused)) signed int *const _X10_retval_f3KPi_1;
 }
+struct _conc__tuple2_3;
 struct _conc__tuple2_3 {
     signed int *field_0;
Index: tests/.expect/poly-cycle.txt
===================================================================
--- tests/.expect/poly-cycle.txt	(revision 3f06c054c29fad4a3749737f921921586777df75)
+++ tests/.expect/poly-cycle.txt	(revision 3f06c054c29fad4a3749737f921921586777df75)
@@ -0,0 +1,1 @@
+Success!
Index: tests/poly-cycle.cfa
===================================================================
--- tests/poly-cycle.cfa	(revision 3f06c054c29fad4a3749737f921921586777df75)
+++ tests/poly-cycle.cfa	(revision 3f06c054c29fad4a3749737f921921586777df75)
@@ -0,0 +1,28 @@
+// Check that a cycle of polymorphic data structures can be instancated.
+
+#include <stdio.h>
+
+forall(otype T)
+struct func_table;
+
+forall(otype U)
+struct object {
+	func_table(U) * virtual_table;
+};
+
+forall(otype T)
+struct func_table {
+	void (*object_func)(object(T) *);
+};
+
+void func(object(int) *) {
+	printf("Success!\n");
+}
+
+func_table(int) an_instance = { func };
+
+int main(int argc, char * argv[]) {
+	object(int) x = { 0p };
+	an_instance.object_func( &x );
+	return 0;
+}
