Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/CodeGen/CodeGenerator.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -83,5 +83,5 @@
 	}
 
-	CodeGenerator::CodeGenerator( std::ostream & os ) : indent( *this), cur_indent( 0 ), insideFunction( false ), output( os ), printLabels( *this ) {}
+	CodeGenerator::CodeGenerator( std::ostream & os, bool mangle ) : indent( *this), cur_indent( 0 ), insideFunction( false ), output( os ), printLabels( *this ), mangle( mangle ) {}
 
 	CodeGenerator::CodeGenerator( std::ostream & os, std::string init, int indentation, bool infunp )
@@ -95,5 +95,6 @@
 	}
 
-	string mangleName( DeclarationWithType * decl ) {
+	string CodeGenerator::mangleName( DeclarationWithType * decl ) {
+		if ( ! mangle ) return decl->get_name();
 		if ( decl->get_mangleName() != "" ) {
 			// need to incorporate scope level in order to differentiate names for destructors
@@ -311,5 +312,5 @@
 							Type * type = InitTweak::getPointerBase( (*arg)->get_results().front() );
 							assert( type );
-							newExpr->get_results().push_back( type );
+							newExpr->get_results().push_back( type->clone() );
 							*arg = newExpr;
 						} // if
Index: src/CodeGen/CodeGenerator.h
===================================================================
--- src/CodeGen/CodeGenerator.h	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/CodeGen/CodeGenerator.h	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -30,5 +30,5 @@
 		static int tabsize;
 
-		CodeGenerator( std::ostream &os );
+		CodeGenerator( std::ostream &os, bool mangle = true );
 		CodeGenerator( std::ostream &os, std::string, int indent = 0, bool infun = false );
 		CodeGenerator( std::ostream &os, char *, int indent = 0, bool infun = false );
@@ -114,4 +114,5 @@
 		std::ostream &output;
 		LabelPrinter printLabels;
+		bool mangle = true;
 
 		void printDesignators( std::list< Expression * > & );
@@ -119,4 +120,5 @@
 		void handleAggregate( AggregateDecl *aggDecl );
 		void handleTypedef( NamedTypeDecl *namedType );
+		std::string mangleName( DeclarationWithType * decl );
 	}; // CodeGenerator
 
Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/CodeGen/GenType.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenType.cc -- 
+// GenType.cc --
 //
 // Author           : Richard C. Bilson
@@ -28,8 +28,8 @@
 	class GenType : public Visitor {
 	  public:
-		GenType( const std::string &typeString );
+		GenType( const std::string &typeString, bool mangle = true );
 		std::string get_typeString() const { return typeString; }
 		void set_typeString( const std::string &newValue ) { typeString = newValue; }
-  
+
 		virtual void visit( FunctionType *funcType );
 		virtual void visit( VoidType *voidType );
@@ -42,19 +42,20 @@
 		virtual void visit( TypeInstType *typeInst );
 		virtual void visit( VarArgsType *varArgsType );
-  
+
 	  private:
 		void handleQualifiers( Type *type );
 		void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
-  
+
 		std::string typeString;
+		bool mangle = true;
 	};
 
-	std::string genType( Type *type, const std::string &baseString ) {
-		GenType gt( baseString );
+	std::string genType( Type *type, const std::string &baseString, bool mangle ) {
+		GenType gt( baseString, mangle );
 		type->accept( gt );
 		return gt.get_typeString();
 	}
 
-	GenType::GenType( const std::string &typeString ) : typeString( typeString ) {}
+	GenType::GenType( const std::string &typeString, bool mangle ) : typeString( typeString ), mangle( mangle ) {}
 
 	void GenType::visit( VoidType *voidType ) {
@@ -100,5 +101,5 @@
 		} // if
 		if ( dimension != 0 ) {
-			CodeGenerator cg( os );
+			CodeGenerator cg( os, mangle );
 			dimension->accept( cg );
 		} else if ( isVarLen ) {
@@ -109,5 +110,5 @@
 
 		typeString = os.str();
-  
+
 		base->accept( *this );
 	}
@@ -142,5 +143,5 @@
 			} // if
 		} // if
-  
+
 		/************* parameters ***************/
 
@@ -154,5 +155,5 @@
 			} // if
 		} else {
-			CodeGenerator cg( os );
+			CodeGenerator cg( os, mangle );
 			os << "(" ;
 
@@ -164,5 +165,5 @@
 			os << ")";
 		} // if
-  
+
 		typeString = os.str();
 
Index: src/CodeGen/GenType.h
===================================================================
--- src/CodeGen/GenType.h	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/CodeGen/GenType.h	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenType.h -- 
+// GenType.h --
 //
 // Author           : Richard C. Bilson
@@ -21,5 +21,5 @@
 
 namespace CodeGen {
-	std::string genType( Type *type, const std::string &baseString );
+	std::string genType( Type *type, const std::string &baseString, bool mangle = true );
 } // namespace CodeGen
 
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/Common/utility.h	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -144,7 +144,18 @@
 
 template < typename T >
-std::string toString ( T value ) {
+void toString_single ( std::ostream & os, const T & value ) {
+	os << value;
+}
+
+template < typename T, typename... Params >
+void toString_single ( std::ostream & os, const T & value, const Params & ... params ) {
+	os << value;
+	toString_single( os, params ... );
+}
+
+template < typename ... Params >
+std::string toString ( const Params & ... params ) {
 	std::ostringstream os;
-	os << value; // << std::ends;
+	toString_single( os, params... );
 	return os.str();
 }
@@ -218,4 +229,21 @@
 }
 
+template< typename T >
+void warn_single( const T & arg ) {
+	std::cerr << arg << std::endl;
+}
+
+template< typename T, typename... Params >
+void warn_single(const T & arg, const Params & ... params ) {
+	std::cerr << arg;
+	warn_single( params... );
+}
+
+template< typename... Params >
+void warn( const Params & ... params ) {
+	std::cerr << "Warning: ";
+	warn_single( params... );
+}
+
 #endif // _UTILITY_H
 
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/InitTweak/FixInit.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -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;
@@ -284,5 +314,5 @@
 			UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) );
 			untyped->get_args().push_back( new AddressExpr( new VariableExpr( var ) ) );
-			if (cpArg) untyped->get_args().push_back( cpArg );
+			if (cpArg) untyped->get_args().push_back( cpArg->clone() );
 
 			// resolve copy constructor
@@ -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(), false ), ", 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() ) ) return;
+
+			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(), false ), ", 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 c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/InitTweak/InitTweak.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -291,9 +291,16 @@
 	}
 
+	namespace {
+		template <typename Predicate>
+		bool allofCtorDtor( Statement * stmt, const Predicate & pred ) {
+			std::list< Expression * > callExprs;
+			collectCtorDtorCalls( stmt, callExprs );
+			// if ( callExprs.empty() ) return false; // xxx - do I still need this check?
+			return std::all_of( callExprs.begin(), callExprs.end(), pred);
+		}
+	}
+
 	bool isIntrinsicSingleArgCallStmt( Statement * stmt ) {
-		std::list< Expression * > callExprs;
-		collectCtorDtorCalls( stmt, callExprs );
-		// if ( callExprs.empty() ) return false; // xxx - do I still need this check?
-		return std::all_of( callExprs.begin(), callExprs.end(), []( Expression * callExpr ){
+		return allofCtorDtor( stmt, []( Expression * callExpr ){
 			if ( ApplicationExpr * appExpr = isIntrinsicCallExpr( callExpr ) ) {
 				assert( ! appExpr->get_function()->get_results().empty() );
@@ -303,4 +310,10 @@
 			}
 			return false;
+		});
+	}
+
+	bool isIntrinsicCallStmt( Statement * stmt ) {
+		return allofCtorDtor( stmt, []( Expression * callExpr ) {
+			return isIntrinsicCallExpr( callExpr );
 		});
 	}
@@ -420,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 c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/InitTweak/InitTweak.h	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -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 );
@@ -41,5 +45,8 @@
 	/// Intended to be used for default ctor/dtor calls, but might have use elsewhere.
 	/// Currently has assertions that make it less than fully general.
-	bool isIntrinsicSingleArgCallStmt( Statement * expr );
+	bool isIntrinsicSingleArgCallStmt( Statement * stmt );
+
+	/// True if stmt is a call statement where the function called is intrinsic.
+	bool isIntrinsicCallStmt( Statement * stmt );
 
 	/// get all Ctor/Dtor call expressions from a Statement
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/Parser/DeclarationNode.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -50,7 +50,7 @@
 	newnode->isInline = isInline;
 	newnode->isNoreturn = isNoreturn;
-	newnode->bitfieldWidth = bitfieldWidth;
+	newnode->bitfieldWidth = maybeClone( bitfieldWidth );
 	newnode->hasEllipsis = hasEllipsis;
-	newnode->initializer = initializer;
+	newnode->initializer = maybeClone( initializer );
 	newnode->set_next( maybeClone( get_next() ) );
 	newnode->linkage = linkage;
@@ -823,4 +823,5 @@
 					*out++ = decl;
 				} // if
+				delete extr;
 			} // if
 			Declaration *decl = cur->build();
Index: src/Parser/LinkageSpec.cc
===================================================================
--- src/Parser/LinkageSpec.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/Parser/LinkageSpec.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -5,6 +5,6 @@
 // file "LICENCE" distributed with Cforall.
 //
-// LinkageSpec.cc -- 
-// 
+// LinkageSpec.cc --
+//
 // Author           : Rodolfo G. Esteves
 // Created On       : Sat May 16 13:22:09 2015
@@ -12,5 +12,5 @@
 // Last Modified On : Sun Aug 21 12:32:53 2016
 // Update Count     : 17
-// 
+//
 
 #include <string>
@@ -32,4 +32,5 @@
 
 std::string LinkageSpec::toString( LinkageSpec::Spec linkage ) {
+	assert( linkage >= 0 && linkage < LinkageSpec::NoOfSpecs );
 	static const char *linkageKinds[LinkageSpec::NoOfSpecs] = {
 		"intrinsic", "Cforall", "C", "automatically generated", "compiler built-in",
@@ -39,7 +40,8 @@
 
 bool LinkageSpec::isDecoratable( Spec spec ) {
+	assert( spec >= 0 && spec < LinkageSpec::NoOfSpecs );
 	static bool decoratable[LinkageSpec::NoOfSpecs] = {
 		//	Intrinsic,	Cforall,	C,		AutoGen,	Compiler
-			true,		true,		false,	true,		false, 
+			true,		true,		false,	true,		false,
 	};
 	return decoratable[spec];
@@ -47,7 +49,8 @@
 
 bool LinkageSpec::isGeneratable( Spec spec ) {
+	assert( spec >= 0 && spec < LinkageSpec::NoOfSpecs );
 	static bool generatable[LinkageSpec::NoOfSpecs] = {
 		//	Intrinsic,	Cforall,	C,		AutoGen,	Compiler
-			true,		true,		true,	true,		false, 
+			true,		true,		true,	true,		false,
 	};
 	return generatable[spec];
@@ -55,7 +58,8 @@
 
 bool LinkageSpec::isOverridable( Spec spec ) {
+	assert( spec >= 0 && spec < LinkageSpec::NoOfSpecs );
 	static bool overridable[LinkageSpec::NoOfSpecs] = {
 		//	Intrinsic,	Cforall,	C,		AutoGen,	Compiler
-			true,		false,		false,	true,		false, 
+			true,		false,		false,	true,		false,
 	};
 	return overridable[spec];
@@ -63,7 +67,8 @@
 
 bool LinkageSpec::isBuiltin( Spec spec ) {
+	assert( spec >= 0 && spec < LinkageSpec::NoOfSpecs );
 	static bool builtin[LinkageSpec::NoOfSpecs] = {
 		//	Intrinsic,	Cforall,	C,		AutoGen,	Compiler
-			true,		false,		false,	false,		true, 
+			true,		false,		false,	false,		true,
 	};
 	return builtin[spec];
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/Parser/ParseNode.h	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -109,5 +109,5 @@
 	ExpressionNode( const ExpressionNode &other );
 	virtual ~ExpressionNode() {}
-	virtual ExpressionNode *clone() const { assert( false ); return nullptr; }
+	virtual ExpressionNode *clone() const { return expr ? new ExpressionNode( expr->clone() ) : nullptr; }
 
 	bool get_extension() const { return extension; }
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/Parser/StatementNode.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -44,5 +44,5 @@
 			agg = decl;
 		} // if
-		stmt.reset( new DeclStmt( noLabels, maybeBuild< Declaration >(agg) ) );
+		stmt.reset( new DeclStmt( noLabels, maybeMoveBuild< Declaration >(agg) ) );
 	} else {
 		assert( false );
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/Parser/TypeData.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -182,5 +182,5 @@
 		break;
 	  case Array:
-		newtype->array->dimension = array->dimension;
+		newtype->array->dimension = maybeClone( array->dimension );
 		newtype->array->isVarLen = array->isVarLen;
 		newtype->array->isStatic = array->isStatic;
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -244,5 +244,5 @@
 		for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
 			if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
-				alternatives.push_back( Alternative( new MemberExpr( dwt->clone(), expr->clone() ), env, newCost ) );
+				alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) );
 				renameTypes( alternatives.back().expr );
 			} else {
@@ -418,5 +418,5 @@
 	// /// Map of declaration uniqueIds (intended to be the assertions in an AssertionSet) to their parents and the number of times they've been included
 	//typedef std::unordered_map< UniqueId, std::unordered_map< UniqueId, unsigned > > AssertionParentSet;
-	
+
 	static const int recursionLimit = /*10*/ 4;  ///< Limit to depth of recursion satisfaction
 	//static const unsigned recursionParentLimit = 1;  ///< Limit to the number of times an assertion can recursively use itself
@@ -429,7 +429,7 @@
 		}
 	}
-	
+
 	template< typename ForwardIterator, typename OutputIterator >
-	void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/ 
+	void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/
 						 int level, const SymTab::Indexer &indexer, OutputIterator out ) {
 		if ( begin == end ) {
@@ -469,5 +469,5 @@
 				std::cerr << std::endl;
 			)
-			
+
 			AssertionSet newHave, newerNeed( newNeed );
 			TypeEnvironment newEnv( newAlt.env );
@@ -847,5 +847,5 @@
 		for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
 			if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
-				alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt->clone() ), env, Cost::zero ) );
+				alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
 				renameTypes( alternatives.back().expr );
 			} else {
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/ResolvExpr/Resolver.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -446,7 +446,18 @@
 		} else if ( StructInstType * st = dynamic_cast< StructInstType * >( initContext ) ) {
 			resolveAggrInit( st->get_baseStruct(), iter, end );
-		} else if ( UnionInstType *st = dynamic_cast< UnionInstType * >( initContext ) ) {
+		} else if ( UnionInstType * st = dynamic_cast< UnionInstType * >( initContext ) ) {
 			resolveAggrInit( st->get_baseUnion(), iter, end );
+		} else if ( TypeInstType * tt = dynamic_cast< TypeInstType * >( initContext ) ) {
+			Type * base = tt->get_baseType()->get_base();
+			if ( base ) {
+				// know the implementation type, so try using that as the initContext
+				initContext = base;
+				visit( listInit );
+			} else {
+				// missing implementation type -- might be an unknown type variable, so try proceeding with the current init context
+				Visitor::visit( listInit );
+			}
 		} else {
+			assert( dynamic_cast< BasicType * >( initContext ) || dynamic_cast< PointerType * >( initContext ) );
 			// basic types are handled here
 			Visitor::visit( listInit );
@@ -539,14 +550,19 @@
 		}
 
-		// xxx - todo
-		// if ( InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
-		// 	// can reduce the constructor down to a SingleInit using the
-		// 	// second argument from the ctor call
-		// }
-
 		if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->get_dtor() ) ) {
 			delete ctorInit->get_dtor();
 			ctorInit->set_dtor( NULL );
 		}
+
+		// xxx - todo -- what about arrays?
+		// if ( dtor == NULL && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
+		// 	// can reduce the constructor down to a SingleInit using the
+		// 	// second argument from the ctor call, since
+		// 	delete ctorInit->get_ctor();
+		// 	ctorInit->set_ctor( NULL );
+
+		// 	Expression * arg =
+		// 	ctorInit->set_init( new SingleInit( arg ) );
+		// }
 	}
 } // namespace ResolvExpr
Index: src/ResolvExpr/TypeEnvironment.cc
===================================================================
--- src/ResolvExpr/TypeEnvironment.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/ResolvExpr/TypeEnvironment.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// TypeEnvironment.cc -- 
+// TypeEnvironment.cc --
 //
 // Author           : Richard C. Bilson
@@ -23,4 +23,53 @@
 
 namespace ResolvExpr {
+	// adding this comparison operator significantly improves assertion resolution run time for
+	// some cases. The current resolution algorithm's speed partially depends on the order of
+	// assertions. Assertions which have fewer possible matches should appear before
+	// assertions which have more possible matches. This seems to imply that this could
+	// be further improved by providing an indexer as an additional argument and ordering based
+	// on the number of matches of the same kind (object, function) for the names of the
+	// declarations.
+	//
+	// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this comparator.
+	bool AssertCompare::operator()( DeclarationWithType * d1, DeclarationWithType * d2 ) {
+			// Objects are always less than functions
+			if ( ObjectDecl * objectDecl1 = dynamic_cast< ObjectDecl * >( d1 ) ) {
+				if ( ObjectDecl * objectDecl2 = dynamic_cast< ObjectDecl * >( d2 ) ) {
+					// objects are ordered by name then type pointer, in that order
+					int cmp = objectDecl1->get_name().compare( objectDecl2->get_name() );
+					return cmp < 0 ||
+						( cmp == 0 && objectDecl1->get_type() < objectDecl2->get_type() );
+				} else {
+					return true;
+				}
+			} else if ( FunctionDecl * funcDecl1 = dynamic_cast< FunctionDecl * >( d1 ) ) {
+				if ( FunctionDecl * funcDecl2 = dynamic_cast< FunctionDecl * >( d2 ) ) {
+					// functions are ordered by name, # parameters, # returnVals, type pointer in that order
+					FunctionType * ftype1 = funcDecl1->get_functionType();
+					FunctionType * ftype2 = funcDecl2->get_functionType();
+					int numThings1 = ftype1->get_parameters().size() + ftype1->get_returnVals().size();
+					int numThings2 = ftype2->get_parameters().size() + ftype2->get_returnVals().size();
+					if ( numThings1 < numThings2 ) return true;
+					if ( numThings1 > numThings2 ) return false;
+
+					// if ( ftype1->get_parameters().size() < ftype2->get_parameters().size() ) return true;
+					// else if ( ftype1->get_parameters().size() > ftype2->get_parameters().size() ) return false;
+					// // same number of parameters
+					// if ( ftype1->get_returnVals().size() < ftype2->get_returnVals().size() ) return true;
+					// else if ( ftype1->get_returnVals().size() > ftype2->get_returnVals().size() ) return false;
+					// same number of return vals
+					// int cmp = funcDecl1->get_name().compare( funcDecl2->get_name() );
+					// if ( cmp < 0 ) return true;
+					// else if ( cmp > 0 ) return false;
+					// // same name
+					return ftype1 < ftype2;
+				} else {
+					return false;
+				}
+			} else {
+				assert( false );
+			}
+		}
+
 	void printAssertionSet( const AssertionSet &assertions, std::ostream &os, int indent ) {
 		for ( AssertionSet::const_iterator i = assertions.begin(); i != assertions.end(); ++i ) {
Index: src/ResolvExpr/TypeEnvironment.h
===================================================================
--- src/ResolvExpr/TypeEnvironment.h	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/ResolvExpr/TypeEnvironment.h	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// TypeEnvironment.h -- 
+// TypeEnvironment.h --
 //
 // Author           : Richard C. Bilson
@@ -28,5 +28,8 @@
 
 namespace ResolvExpr {
-	typedef std::map< DeclarationWithType*, bool > AssertionSet;
+	struct AssertCompare {
+		bool operator()( DeclarationWithType * d1, DeclarationWithType * d2 );
+	};
+	typedef std::map< DeclarationWithType*, bool, AssertCompare > AssertionSet;
 	typedef std::map< std::string, TypeDecl::Kind > OpenVarSet;
 
@@ -39,5 +42,5 @@
 		bool allowWidening;
 		TypeDecl::Kind kind;
-  
+
 		void initialize( const EqvClass &src, EqvClass &dest );
 		EqvClass();
@@ -62,5 +65,5 @@
 		void extractOpenVars( OpenVarSet &openVars ) const;
 		TypeEnvironment *clone() const { return new TypeEnvironment( *this ); }
-  
+
 		typedef std::list< EqvClass >::iterator iterator;
 		iterator begin() { return env.begin(); }
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/ResolvExpr/Unify.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -484,13 +484,13 @@
 		FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
 		if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
-
-			if ( unifyDeclList( functionType->get_parameters().begin(), functionType->get_parameters().end(), otherFunction->get_parameters().begin(), otherFunction->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
-
-				if ( unifyDeclList( functionType->get_returnVals().begin(), functionType->get_returnVals().end(), otherFunction->get_returnVals().begin(), otherFunction->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
-
-					markAssertions( haveAssertions, needAssertions, functionType );
-					markAssertions( haveAssertions, needAssertions, otherFunction );
-
-					result = true;
+			if ( functionType->get_parameters().size() == otherFunction->get_parameters().size() && functionType->get_returnVals().size() == otherFunction->get_returnVals().size() ) {
+				if ( unifyDeclList( functionType->get_parameters().begin(), functionType->get_parameters().end(), otherFunction->get_parameters().begin(), otherFunction->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
+					if ( unifyDeclList( functionType->get_returnVals().begin(), functionType->get_returnVals().end(), otherFunction->get_returnVals().begin(), otherFunction->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
+
+						markAssertions( haveAssertions, needAssertions, functionType );
+						markAssertions( haveAssertions, needAssertions, otherFunction );
+
+						result = true;
+					} // if
 				} // if
 			} // if
Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/SymTab/Autogen.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -68,5 +68,5 @@
 		copy->get_args().push_back( new VariableExpr( dstParam ) );
 		copy->get_args().push_back( new AddressExpr( new VariableExpr( srcParam ) ) );
-		copy->get_args().push_back( new SizeofExpr( unionType ) );
+		copy->get_args().push_back( new SizeofExpr( srcParam->get_type()->clone() ) );
 
 		*out++ = new ExprStmt( noLabels, copy );
@@ -420,8 +420,30 @@
 		copyCtorDecl->set_statements( assignDecl->get_statements()->clone() );
 
+		// create a constructor which takes the first member type as a parameter.
+		// for example, for Union A { int x; double y; }; generate
+		// void ?{}(A *, int)
+		// This is to mimic C's behaviour which initializes the first member of the union.
+		std::list<Declaration *> memCtors;
+		for ( Declaration * member : aggregateDecl->get_members() ) {
+			if ( DeclarationWithType * field = dynamic_cast< DeclarationWithType * >( member ) ) {
+				ObjectDecl * srcParam = new ObjectDecl( "src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, field->get_type()->clone(), 0 );
+
+				FunctionType * memCtorType = ctorType->clone();
+				memCtorType->get_parameters().push_back( srcParam );
+				FunctionDecl * ctor = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, memCtorType, new CompoundStmt( noLabels ), true, false );
+				ctor->fixUniqueId();
+
+				makeUnionFieldsAssignment( srcParam, dstParam, cloneWithParams( refType, unionParams ), back_inserter( ctor->get_statements()->get_kids() ) );
+				memCtors.push_back( ctor );
+				// only generate a ctor for the first field
+				break;
+			}
+		}
+
 		declsToAdd.push_back( assignDecl );
 		declsToAdd.push_back( ctorDecl );
 		declsToAdd.push_back( copyCtorDecl );
 		declsToAdd.push_back( dtorDecl );
+		declsToAdd.splice( declsToAdd.end(), memCtors );
 	}
 
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/SymTab/Validate.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -58,4 +58,5 @@
 #include "Autogen.h"
 #include "ResolvExpr/typeops.h"
+#include <algorithm>
 
 #define debugPrint( x ) if ( doDebug ) { std::cout << x; }
@@ -162,5 +163,7 @@
 
 		typedef std::map< std::string, std::pair< TypedefDecl *, int > > TypedefMap;
+		typedef std::map< std::string, TypeDecl * > TypeDeclMap;
 		TypedefMap typedefNames;
+		TypeDeclMap typedeclNames;
 		int scopeLevel;
 	};
@@ -370,5 +373,9 @@
 		} // if
 
-		applySubstitution( ctx->get_parameters().begin(), ctx->get_parameters().end(), contextInst->get_parameters().begin(), ctx->get_members().begin(), ctx->get_members().end(), back_inserter( contextInst->get_members() ) );
+		// need to clone members of the context for ownership purposes
+		std::list< Declaration * > members;
+		std::transform( ctx->get_members().begin(), ctx->get_members().end(), back_inserter( members ), [](Declaration * dwt) { return dwt->clone(); } );
+
+		applySubstitution( ctx->get_parameters().begin(), ctx->get_parameters().end(), contextInst->get_parameters().begin(), members.begin(), members.end(), back_inserter( contextInst->get_members() ) );
 	}
 
@@ -521,4 +528,8 @@
 			delete typeInst;
 			return ret;
+		} else {
+			TypeDeclMap::const_iterator base = typedeclNames.find( typeInst->get_name() );
+			assert( base != typedeclNames.end() );
+			typeInst->set_baseType( base->second->clone() );
 		} // if
 		return typeInst;
@@ -565,4 +576,6 @@
 			typedefNames.erase( i ) ;
 		} // if
+
+		typedeclNames[ typeDecl->get_name() ] = typeDecl;
 		return typeDecl;
 	}
Index: src/SynTree/AggregateDecl.cc
===================================================================
--- src/SynTree/AggregateDecl.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/SynTree/AggregateDecl.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// AggregateDecl.cc -- 
+// AggregateDecl.cc --
 //
 // Author           : Richard C. Bilson
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/SynTree/Expression.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -200,9 +200,8 @@
 
 OffsetofExpr::OffsetofExpr( const OffsetofExpr &other ) :
-	Expression( other ), type( maybeClone( other.type ) ), member( maybeClone( other.member ) ) {}
+	Expression( other ), type( maybeClone( other.type ) ), member( other.member ) {}
 
 OffsetofExpr::~OffsetofExpr() {
 	delete type;
-	delete member;
 }
 
@@ -359,4 +358,5 @@
 	assert( member );
 	os << std::string( indent + 2, ' ' );
+	os << (void*)member << " ";
 	member->print( os, indent + 2 );
 	os << std::endl;
@@ -385,5 +385,5 @@
 UntypedExpr::~UntypedExpr() {
 	delete function;
-	// deleteAll( args );  //TODO FIXME the arguments are leaked but they seem to be shared in some way
+	deleteAll( args );
 }
 
Index: src/SynTree/Initializer.cc
===================================================================
--- src/SynTree/Initializer.cc	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/SynTree/Initializer.cc	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -43,4 +43,5 @@
 
 SingleInit::~SingleInit() {
+	delete value;
 	deleteAll(designators);
 }
Index: src/SynTree/TypeSubstitution.h
===================================================================
--- src/SynTree/TypeSubstitution.h	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/SynTree/TypeSubstitution.h	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -169,7 +169,6 @@
 	TypeSubstitution sub = TypeSubstitution( formalBegin, formalEnd, actual );
 	for ( std::list< Declaration* >::iterator i = memberBegin; i != memberEnd; ++i ) {
-		Declaration *newdecl = (*i)->clone();
-		sub.apply( newdecl );
-		*out++ = newdecl;
+		sub.apply( *i );
+		*out++ = *i;
 	} // for
 }
Index: src/tests/.expect/32/extension.txt
===================================================================
--- src/tests/.expect/32/extension.txt	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/tests/.expect/32/extension.txt	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -70,4 +70,9 @@
 static inline void ___destructor__F_P2uU_autogen___1(union U *___dst__P2uU_1){
 }
+static inline void ___constructor__F_P2uUi_autogen___1(union U *___dst__P2uU_1, int __src__i_1){
+    void *_tmp_cp_ret2;
+    ((void)((_tmp_cp_ret2=__builtin_memcpy(((void *)___dst__P2uU_1), ((const void *)(&__src__i_1)), sizeof(int ))) , _tmp_cp_ret2));
+    ((void)(_tmp_cp_ret2) /* ^?{} */);
+}
 __extension__ enum E {
     __R__C2eE_1,
@@ -89,7 +94,7 @@
     __extension__ int __c__i_2;
     ((void)(__extension__ __a__i_2=(__extension__ __b__i_2+__extension__ __c__i_2)));
-    int _tmp_cp_ret2;
-    ((void)((_tmp_cp_ret2=__extension__ __fred__Fi_i__1(3)) , _tmp_cp_ret2));
-    ((void)(_tmp_cp_ret2) /* ^?{} */);
+    int _tmp_cp_ret3;
+    ((void)((_tmp_cp_ret3=__extension__ __fred__Fi_i__1(3)) , _tmp_cp_ret3));
+    ((void)(_tmp_cp_ret3) /* ^?{} */);
     ((void)__extension__ sizeof(3));
     ((void)__extension__ (((int )(3!=0)) || ((int )(4!=0))));
Index: src/tests/.expect/64/extension.txt
===================================================================
--- src/tests/.expect/64/extension.txt	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/tests/.expect/64/extension.txt	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -70,4 +70,9 @@
 static inline void ___destructor__F_P2uU_autogen___1(union U *___dst__P2uU_1){
 }
+static inline void ___constructor__F_P2uUi_autogen___1(union U *___dst__P2uU_1, int __src__i_1){
+    void *_tmp_cp_ret2;
+    ((void)((_tmp_cp_ret2=__builtin_memcpy(((void *)___dst__P2uU_1), ((const void *)(&__src__i_1)), sizeof(int ))) , _tmp_cp_ret2));
+    ((void)(_tmp_cp_ret2) /* ^?{} */);
+}
 __extension__ enum E {
     __R__C2eE_1,
@@ -89,7 +94,7 @@
     __extension__ int __c__i_2;
     ((void)(__extension__ __a__i_2=(__extension__ __b__i_2+__extension__ __c__i_2)));
-    int _tmp_cp_ret2;
-    ((void)((_tmp_cp_ret2=__extension__ __fred__Fi_i__1(3)) , _tmp_cp_ret2));
-    ((void)(_tmp_cp_ret2) /* ^?{} */);
+    int _tmp_cp_ret3;
+    ((void)((_tmp_cp_ret3=__extension__ __fred__Fi_i__1(3)) , _tmp_cp_ret3));
+    ((void)(_tmp_cp_ret3) /* ^?{} */);
     ((void)__extension__ sizeof(3));
     ((void)__extension__ (((int )(3!=0)) || ((int )(4!=0))));
Index: src/tests/.expect/ctorWarnings.txt
===================================================================
--- src/tests/.expect/ctorWarnings.txt	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
+++ src/tests/.expect/ctorWarnings.txt	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -0,0 +1,7 @@
+CFA Version 1.0.0 (debug)
+Warning: in void ?{}(struct A *a, int x), member z may not have been constructed
+Warning: in void ?{}(struct B *b), member a2 used before being constructed
+Warning: in void ?{}(struct B *b), member a2 may not have been constructed
+Warning: in void ?{}(struct B *b), member a3 may not have been constructed
+Warning: in void ^?{}(struct B *b), member a2 may not have been destructed
+Warning: in void ^?{}(struct B *b), member a3 may not have been destructed
Index: src/tests/Makefile.am
===================================================================
--- src/tests/Makefile.am	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/tests/Makefile.am	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -62,2 +62,5 @@
 	${CC} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@}
 
+ctorWarnings: ctorWarnings.c
+	${CC} ${CFALGS} -CFA -XCFA -p ${<} -o /dev/null 2> ${@}
+
Index: src/tests/Makefile.in
===================================================================
--- src/tests/Makefile.in	(revision c1c11129b7b459ededc97d8b5200227481c001a9)
+++ src/tests/Makefile.in	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -670,4 +670,7 @@
 	${CC} ${CFLAGS} -CFA -XCFA -p ${<} -o ${@}
 
+ctorWarnings: ctorWarnings.c
+	${CC} ${CFALGS} -CFA -XCFA -p ${<} -o /dev/null 2> ${@}
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
Index: src/tests/ctorWarnings.c
===================================================================
--- src/tests/ctorWarnings.c	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
+++ src/tests/ctorWarnings.c	(revision 4e2b97109c2f3a8707de4cdb9e9d0a4fb27b63f1)
@@ -0,0 +1,26 @@
+struct A {
+  int x, y, z;
+};
+
+void ?{}(A * a, int x) {
+  (&a->x){ x+999 };
+  a->y = 0; // not technically a constructor, but okay
+} // z never constructed
+
+struct B {
+  A a1, a2, a3;
+};
+
+void ?{}(B * b) {
+  b->a2 = (A) { 2 }; // a2 used before constructed
+  (&b->a1){ 1 };
+} // a2, a3 never constructed
+
+void ^?{}(B * b) {
+  b->a2 = (A) { 0 };
+  ^(&b->a1){};
+} // a2, a3 never destructed
+
+int main() {
+  B b;
+}
