Index: src/CodeTools/DeclStats.cc
===================================================================
--- src/CodeTools/DeclStats.cc	(revision 65e9bc1829e43db0a1b7848a068ab4715b6e2f2d)
+++ src/CodeTools/DeclStats.cc	(revision 0e7ea3359ca310e007b848d916a4c58b671ed6c8)
@@ -186,4 +186,5 @@
 			auto& args = expr->get_args();
 			unsigned fanout = args.size();
+			
 			++exprs_by_fanout_at_depth[ std::make_pair(depth, fanout) ];
 			for ( Expression* arg : args ) {
Index: src/GenPoly/InstantiateGeneric.cc
===================================================================
--- src/GenPoly/InstantiateGeneric.cc	(revision 65e9bc1829e43db0a1b7848a068ab4715b6e2f2d)
+++ src/GenPoly/InstantiateGeneric.cc	(revision 0e7ea3359ca310e007b848d916a4c58b671ed6c8)
@@ -226,6 +226,20 @@
 
 			if ( (*baseParam)->isComplete() ) {
-				// substitute parameter for complete (otype or sized dtype) type; makes the struct concrete or dynamic depending on the parameter
-				out.push_back( paramType->clone() );
+				// substitute parameter for complete (otype or sized dtype) type
+				int pointerLevels = 0;
+				if ( hasPolyBase( paramType->get_type(), &pointerLevels ) && pointerLevels > 0 ) {
+					// Make a void* with equivalent nesting
+					Type* voidPtr = new VoidType( Type::Qualifiers() );
+					while ( pointerLevels > 0 ) {
+						// Just about data layout, so qualifiers *shouldn't* matter
+						voidPtr = new PointerType( Type::Qualifiers(), voidPtr );
+						--pointerLevels;
+					}
+					out.push_back( new TypeExpr( voidPtr ) );
+				} else {
+					// Just clone parameter type
+					out.push_back( paramType->clone() );
+				}
+				// make the struct concrete or dynamic depending on the parameter
 				gt |= isPolyType( paramType->get_type() ) ? genericType::dynamic : genericType::concrete;
 			} else switch ( (*baseParam)->get_kind() ) {
