Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 72f85dec7bd1577efe1a71cad4da5f10517fe662)
+++ src/InitTweak/FixInit.cc	(revision 88e79ad31c60e292ed0b47c4856a7eddffd05491)
@@ -177,6 +177,4 @@
 			DeclarationWithType * postmutate( ObjectDecl *objDecl );
 
-			DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * dtor );
-
 			std::list< Declaration * > staticDtorDecls;
 		};
@@ -202,4 +200,6 @@
 			static void generate( std::list< Declaration * > & translationUnit );
 
+			void previsit( StructDecl * structDecl );
+
 			void previsit( FunctionDecl * funcDecl );
 			void postvisit( FunctionDecl * funcDecl );
@@ -219,4 +219,8 @@
 			bool isCtor = false; // true if current function is a constructor
 			StructDecl * structDecl = nullptr;
+
+			// special built-in functions necessary for this to work
+			StructDecl * dtorStruct = nullptr;
+			FunctionDecl * dtorStructDestroy = nullptr;
 		};
 
@@ -635,5 +639,5 @@
 		}
 
-		DeclarationWithType * FixInit::getDtorFunc( ObjectDecl * objDecl, Statement * dtor ) {
+		DeclarationWithType * getDtorFunc( ObjectDecl * objDecl, Statement * dtor, std::list< Statement * > & stmtsToAdd ) {
 			if ( dynamic_cast< ExprStmt * >( dtor ) ) {
 				if ( DeclarationWithType * func = getFunction( getCtorDtorCall( dtor ) ) ) {
@@ -653,6 +657,6 @@
 			// wraps the more complicated code.
 			static UniqueName dtorNamer( "__cleanup_dtor" );
-			FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type, false ), new CompoundStmt( noLabels ) );
-			stmtsToAddBefore.push_back( new DeclStmt( noLabels, dtorFunc ) );
+			FunctionDecl * dtorFunc = FunctionDecl::newFunction( dtorNamer.newName(), SymTab::genDefaultType( objDecl->type->stripReferences(), false ), new CompoundStmt( noLabels ) );
+			stmtsToAdd.push_back( new DeclStmt( noLabels, dtorFunc ) );
 
 			// the original code contains uses of objDecl - replace them with the newly generated 'this' parameter.
@@ -785,5 +789,5 @@
 							if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
 								// set dtor location to the object's location for error messages
-								DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt );
+								DeclarationWithType * dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
 								objDecl->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorFunc ) } ) );
 								// objDecl->attributes.push_back( new Attribute( "cleanup", { new NameExpr( dtorFunc->name ) } ) );
@@ -910,4 +914,10 @@
 		}
 
+		void GenStructMemberCalls::previsit( StructDecl * structDecl ) {
+			if ( ! dtorStruct && structDecl->name == "__Destructor" ) {
+				dtorStruct = structDecl;
+			}
+		}
+
 		void GenStructMemberCalls::previsit( FunctionDecl * funcDecl ) {
 			GuardValue( function );
@@ -922,4 +932,9 @@
 			unhandled.clear();
 			usedUninit.clear();
+
+			if ( ! dtorStructDestroy && funcDecl->name == "__destroy_Destructor" ) {
+				dtorStructDestroy = funcDecl;
+				return;
+			}
 
 			function = funcDecl;
@@ -933,4 +948,5 @@
 				if ( structType ) {
 					structDecl = structType->get_baseStruct();
+					if ( structDecl == dtorStruct ) return;
 					for ( Declaration * member : structDecl->get_members() ) {
 						if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
@@ -1004,8 +1020,24 @@
 							callStmt->acceptMutator( resolver );
 							if ( isCtor ) {
-								function->get_statements()->push_front( callStmt );
+								function->statements->push_front( callStmt );
 							} else {
 								// destructor statements should be added at the end
-								function->get_statements()->push_back( callStmt );
+								// function->get_statements()->push_back( callStmt );
+
+								// Destructor _dtor0 = { &b.a1, _destroy_A };
+								std::list< Statement * > stmtsToAdd;
+
+								static UniqueName memberDtorNamer = { "__memberDtor" };
+								assertf( dtorStruct, "builtin __Destructor not found." );
+								assertf( dtorStructDestroy, "builtin __destroy_Destructor not found." );
+
+								Expression * thisExpr = new AddressExpr( new VariableExpr( thisParam ) );
+								Expression * dtorExpr = new VariableExpr( getDtorFunc( thisParam, callStmt, stmtsToAdd ) );
+
+								ObjectDecl * destructor = ObjectDecl::newObject( memberDtorNamer.newName(), new StructInstType( Type::Qualifiers(), dtorStruct ), new ListInit( { new SingleInit( thisExpr ), new SingleInit( dtorExpr ) } ) );
+								function->statements->push_front( new DeclStmt( noLabels, destructor ) );
+								destructor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( dtorStructDestroy ) } ) );
+
+								function->statements->kids.splice( function->statements->kids.begin(), stmtsToAdd );
 							}
 						} catch ( SemanticError & error ) {
Index: src/prelude/builtins.c
===================================================================
--- src/prelude/builtins.c	(revision 72f85dec7bd1577efe1a71cad4da5f10517fe662)
+++ src/prelude/builtins.c	(revision 88e79ad31c60e292ed0b47c4856a7eddffd05491)
@@ -91,4 +91,25 @@
 static inline unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
 
+// type that wraps a pointer and a destructor-like function - used in generating implicit destructor calls for struct members in user-defined functions
+forall(dtype T)
+struct __Destructor {
+  T * object;
+  void (*dtor)(T *);
+};
+
+// defined destructor in the case that non-generated code wants to use __Destructor
+forall(dtype T)
+static inline void ^?{}(__Destructor(T) & x) {
+  x.dtor(x.object);
+}
+
+// easy interface into __Destructor's destructor for easy codegen purposes
+extern "C" {
+  forall(dtype T)
+  static inline void __destroy_Destructor(__Destructor(T) * dtor) {
+    ^(*dtor){};
+  }
+}
+
 // Local Variables: //
 // mode: c //
