Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision f87408e9321946317a275df9cd75d82077dda957)
+++ src/InitTweak/FixInit.cc	(revision 0555f4bcb3f9d01c36c8df66c8417c065804176b)
@@ -33,4 +33,5 @@
 #include "GenPoly/PolyMutator.h"
 #include "SynTree/AddStmtVisitor.h"
+#include "CodeGen/GenType.h"  // for warnings
 
 bool ctordtorp = false;
@@ -174,4 +175,24 @@
 			virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr );
 		};
+
+		class WarnStructMembers : public Visitor {
+		  public:
+			typedef Visitor Parent;
+			/// warn if a user-defined constructor or destructor is missing calls for
+			/// a struct member or if a member is used before constructed
+			static void warnings( std::list< Declaration * > & translationUnit );
+
+			virtual void visit( FunctionDecl * funcDecl );
+
+			virtual void visit( MemberExpr * memberExpr );
+			virtual void visit( ApplicationExpr * appExpr );
+
+		  private:
+			void handleFirstParam( Expression * firstParam );
+
+			FunctionDecl * function = 0;
+			std::set< DeclarationWithType * > unhandled;
+			ObjectDecl * thisParam = 0;
+		};
 	} // namespace
 
@@ -187,4 +208,6 @@
 		// FixCopyCtors must happen after FixInit, so that destructors are placed correctly
 		FixCopyCtors::fixCopyCtors( translationUnit );
+
+		WarnStructMembers::warnings( translationUnit );
 	}
 
@@ -231,4 +254,11 @@
 		}
 
+		void WarnStructMembers::warnings( std::list< Declaration * > & translationUnit ) {
+			if ( true ) { // fix this condition to skip this pass if warnings aren't enabled
+				WarnStructMembers warner;
+				acceptAll( translationUnit, warner );
+			}
+		}
+
 		Expression * InsertImplicitCalls::mutate( ApplicationExpr * appExpr ) {
 			appExpr = dynamic_cast< ApplicationExpr * >( Mutator::mutate( appExpr ) );
@@ -242,5 +272,5 @@
 					FunctionType * ftype = dynamic_cast< FunctionType * >( GenPoly::getFunctionType( funcDecl->get_type() ) );
 					assert( ftype );
-					if ( (funcDecl->get_name() == "?{}" || funcDecl->get_name() == "?=?") && ftype->get_parameters().size() == 2 ) {
+					if ( (isConstructor( funcDecl->get_name() ) || funcDecl->get_name() == "?=?") && ftype->get_parameters().size() == 2 ) {
 						Type * t1 = ftype->get_parameters().front()->get_type();
 						Type * t2 = ftype->get_parameters().back()->get_type();
@@ -253,5 +283,5 @@
 							return appExpr;
 						} // if
-					} else if ( funcDecl->get_name() == "^?{}" ) {
+					} else if ( isDestructor( funcDecl->get_name() ) ) {
 						// correctness: never copy construct arguments to a destructor
 						return appExpr;
@@ -670,4 +700,109 @@
 			} // switch
 		}
+
+		bool checkWarnings( FunctionDecl * funcDecl ) {
+			// only check for warnings if the current function is a user-defined
+			// constructor or destructor
+			if ( ! funcDecl ) return false;
+			if ( ! funcDecl->get_statements() ) return false;
+			return isCtorDtor( funcDecl->get_name() ) && ! LinkageSpec::isOverridable( funcDecl->get_linkage() );
+		}
+
+		void WarnStructMembers::visit( FunctionDecl * funcDecl ) {
+			WarnStructMembers old = *this;
+			*this = WarnStructMembers();
+
+			function = funcDecl;
+			if ( checkWarnings( funcDecl ) ) {
+				FunctionType * type = funcDecl->get_functionType();
+				assert( ! type->get_parameters().empty() );
+				thisParam = safe_dynamic_cast< ObjectDecl * >( type->get_parameters().front() );
+				PointerType * ptrType = safe_dynamic_cast< PointerType * > ( thisParam->get_type() );
+				StructInstType * structType = dynamic_cast< StructInstType * >( ptrType->get_base() );
+				if ( structType ) {
+					StructDecl * structDecl = structType->get_baseStruct();
+					for ( Declaration * member : structDecl->get_members() ) {
+						if ( ObjectDecl * field = dynamic_cast< ObjectDecl * >( member ) ) {
+							// record all of the struct type's members that need to be constructed or
+							// destructed by the end of the function
+							unhandled.insert( field );
+						}
+					}
+				}
+			}
+			Parent::visit( funcDecl );
+
+			for ( DeclarationWithType * member : unhandled ) {
+				// emit a warning for each unhandled member
+				warn( "in ", CodeGen::genType( function->get_functionType(), function->get_name() ), ", member ", member->get_name(), " may not have been ", isConstructor( funcDecl->get_name() ) ? "constructed" : "destructed" );
+			}
+
+			*this = old;
+		}
+
+		void WarnStructMembers::visit( ApplicationExpr * appExpr ) {
+			if ( ! checkWarnings( function ) ) return;
+
+			std::string fname = getFunctionName( appExpr );
+			if ( fname == function->get_name() ) {
+				// call to same kind of function
+				Expression * firstParam = appExpr->get_args().front();
+
+				if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( firstParam ) ) {
+					// if calling another constructor on thisParam, assume that function handles
+					// all members - if it doesn't a warning will appear in that function.
+					if ( varExpr->get_var() == thisParam ) {
+						unhandled.clear();
+					}
+				} else {
+					// if first parameter is a member expression then
+					// remove the member from unhandled set.
+					handleFirstParam( firstParam );
+				}
+			} else if ( fname == "?=?" && isIntrinsicCallExpr( appExpr ) ) {
+				// forgive use of intrinsic assignment to construct, since instrinsic constructors
+				// codegen as assignment anyway.
+				assert( appExpr->get_args().size() == 2 );
+				handleFirstParam( appExpr->get_args().front() );
+			}
+
+			Parent::visit( appExpr );
+		}
+
+		void WarnStructMembers::handleFirstParam( Expression * firstParam ) {
+			using namespace std;
+			if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( firstParam ) ) {
+				if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( addrExpr->get_arg() ) ) {
+					if ( ApplicationExpr * deref = dynamic_cast< ApplicationExpr * >( memberExpr->get_aggregate() ) ) {
+						if ( getFunctionName( deref ) == "*?" && deref->get_args().size() == 1 ) {
+							if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( deref->get_args().front() ) ) {
+								if ( varExpr->get_var() == thisParam ) {
+									unhandled.erase( memberExpr->get_member() );
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+
+		void WarnStructMembers::visit( MemberExpr * memberExpr ) {
+			if ( ! checkWarnings( function ) ) return;
+			if ( ! isConstructor( function->get_name() ) );
+
+			if ( ApplicationExpr * deref = dynamic_cast< ApplicationExpr * >( memberExpr->get_aggregate() ) ) {
+				if ( getFunctionName( deref ) == "*?" && deref->get_args().size() == 1 ) {
+					if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( deref->get_args().front() ) ) {
+						if ( varExpr->get_var() == thisParam ) {
+							if ( unhandled.count( memberExpr->get_member() ) ) {
+								// emit a warning because a member was used before it was constructed
+								warn( "in ", CodeGen::genType( function->get_functionType(), function->get_name() ), ", member ", memberExpr->get_member()->get_name(), " used before being constructed" );
+							}
+						}
+					}
+				}
+			}
+			Parent::visit( memberExpr );
+		}
 	} // namespace
 } // namespace InitTweak
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision f87408e9321946317a275df9cd75d82077dda957)
+++ src/InitTweak/InitTweak.cc	(revision 0555f4bcb3f9d01c36c8df66c8417c065804176b)
@@ -433,3 +433,6 @@
 	}
 
+	bool isConstructor( const std::string & str ) { return str == "?{}"; }
+	bool isDestructor( const std::string & str ) { return str == "^?{}"; }
+	bool isCtorDtor( const std::string & str ) { return isConstructor( str ) || isDestructor( str ); }
 }
Index: src/InitTweak/InitTweak.h
===================================================================
--- src/InitTweak/InitTweak.h	(revision f87408e9321946317a275df9cd75d82077dda957)
+++ src/InitTweak/InitTweak.h	(revision 0555f4bcb3f9d01c36c8df66c8417c065804176b)
@@ -26,4 +26,8 @@
 // helper functions for initialization
 namespace InitTweak {
+	bool isConstructor( const std::string & );
+	bool isDestructor( const std::string & );
+	bool isCtorDtor( const std::string & );
+
 	/// transform Initializer into an argument list that can be passed to a call expression
 	std::list< Expression * > makeInitList( Initializer * init );
