Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 44b70880e982c036e8482060172be8e37b709925)
+++ src/SymTab/Validate.cc	(revision c14cff1813318f9616a9e814d9a8528eb9ddcbf9)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 21:50:04 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jan 27 22:03:12 2016
-// Update Count     : 225
+// Last Modified By : Rob Schluntz
+// Last Modified On : Mon Feb 22 12:26:37 2016
+// Update Count     : 297
 //
 
@@ -202,4 +202,17 @@
 	};
 
+	class VerifyCtorDtor : public Visitor {
+	public:
+		/// ensure that constructors and destructors have at least one
+		/// parameter, the first of which must be a pointer, and no
+		/// return values.
+		static void verify( std::list< Declaration * > &translationUnit );
+
+		// VerifyCtorDtor() {}
+
+		virtual void visit( FunctionDecl *funcDecl );
+	private:
+	};
+
 	void validate( std::list< Declaration * > &translationUnit, bool doDebug ) {
 		Pass1 pass1;
@@ -213,4 +226,5 @@
 		AutogenerateRoutines::autogenerateRoutines( translationUnit );
 		acceptAll( translationUnit, pass3 );
+		VerifyCtorDtor::verify( translationUnit );
 	}
 
@@ -521,10 +535,12 @@
 
 	template< typename OutputIterator >
-	void makeScalarAssignment( ObjectDecl *srcParam, ObjectDecl *dstParam, DeclarationWithType *member, OutputIterator out ) {
+	void makeScalarFunction( ObjectDecl *srcParam, ObjectDecl *dstParam, DeclarationWithType *member, std::string fname, OutputIterator out ) {
 		ObjectDecl *obj = dynamic_cast<ObjectDecl *>( member );
 		// unnamed bit fields are not copied as they cannot be accessed
 		if ( obj != NULL && obj->get_name() == "" && obj->get_bitfieldWidth() != NULL ) return;
 
-		UntypedExpr *assignExpr = new UntypedExpr( new NameExpr( "?=?" ) );
+		// want to be able to generate assignment, ctor, and dtor generically,
+		// so fname is either ?=?, ?{}, or ^?{}
+		UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
 
 		UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
@@ -533,14 +549,14 @@
 		// do something special for unnamed members
 		Expression *dstselect = new AddressExpr( new MemberExpr( member, derefExpr ) );
-		assignExpr->get_args().push_back( dstselect );
+		fExpr->get_args().push_back( dstselect );
 
 		Expression *srcselect = new MemberExpr( member, new VariableExpr( srcParam ) );
-		assignExpr->get_args().push_back( srcselect );
-
-		*out++ = new ExprStmt( noLabels, assignExpr );
+		fExpr->get_args().push_back( srcselect );
+
+		*out++ = new ExprStmt( noLabels, fExpr );
 	}
 
 	template< typename OutputIterator >
-	void makeArrayAssignment( ObjectDecl *srcParam, ObjectDecl *dstParam, DeclarationWithType *member, ArrayType *array, OutputIterator out ) {
+	void makeArrayFunction( ObjectDecl *srcParam, ObjectDecl *dstParam, DeclarationWithType *member, ArrayType *array, std::string fname, OutputIterator out ) {
 		static UniqueName indexName( "_index" );
 
@@ -565,5 +581,7 @@
 		inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
 
-		UntypedExpr *assignExpr = new UntypedExpr( new NameExpr( "?=?" ) );
+		// want to be able to generate assignment, ctor, and dtor generically,
+		// so fname is either ?=?, ?{}, or ^?{}
+		UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
 
 		UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
@@ -574,5 +592,5 @@
 		dstIndex->get_args().push_back( dstselect );
 		dstIndex->get_args().push_back( new VariableExpr( index ) );
-		assignExpr->get_args().push_back( dstIndex );
+		fExpr->get_args().push_back( dstIndex );
 
 		Expression *srcselect = new MemberExpr( member, new VariableExpr( srcParam ) );
@@ -580,7 +598,7 @@
 		srcIndex->get_args().push_back( srcselect );
 		srcIndex->get_args().push_back( new VariableExpr( index ) );
-		assignExpr->get_args().push_back( srcIndex );
-
-		*out++ = new ForStmt( noLabels, initList, cond, inc, new ExprStmt( noLabels, assignExpr ) );
+		fExpr->get_args().push_back( srcIndex );
+
+		*out++ = new ForStmt( noLabels, initList, cond, inc, new ExprStmt( noLabels, fExpr ) );
 	}
 
@@ -732,16 +750,16 @@
 					// assign to both destination and return value
 					if ( ArrayType *array = dynamic_cast< ArrayType * >( fixedMember->get_type() ) ) {
-						makeArrayAssignment( srcParam, dstParam, fixedMember, array, back_inserter( assignDecl->get_statements()->get_kids() ) );
-						makeArrayAssignment( srcParam, returnVal, fixedMember, array, back_inserter( assignDecl->get_statements()->get_kids() ) );
+						makeArrayFunction( srcParam, dstParam, fixedMember, array, "?=?", back_inserter( assignDecl->get_statements()->get_kids() ) );
+						makeArrayFunction( srcParam, returnVal, fixedMember, array, "?=?", back_inserter( assignDecl->get_statements()->get_kids() ) );
 					} else {
-						makeScalarAssignment( srcParam, dstParam, fixedMember, back_inserter( assignDecl->get_statements()->get_kids() ) );
-						makeScalarAssignment( srcParam, returnVal, fixedMember, back_inserter( assignDecl->get_statements()->get_kids() ) );
+						makeScalarFunction( srcParam, dstParam, fixedMember, "?=?", back_inserter( assignDecl->get_statements()->get_kids() ) );
+						makeScalarFunction( srcParam, returnVal, fixedMember, "?=?", back_inserter( assignDecl->get_statements()->get_kids() ) );
 					} // if
 				} else {
 					// assign to destination
 					if ( ArrayType *array = dynamic_cast< ArrayType * >( dwt->get_type() ) ) {
-						makeArrayAssignment( srcParam, dstParam, dwt, array, back_inserter( assignDecl->get_statements()->get_kids() ) );
+						makeArrayFunction( srcParam, dstParam, dwt, array, "?=?", back_inserter( assignDecl->get_statements()->get_kids() ) );
 					} else {
-						makeScalarAssignment( srcParam, dstParam, dwt, back_inserter( assignDecl->get_statements()->get_kids() ) );
+						makeScalarFunction( srcParam, dstParam, dwt, "?=?", back_inserter( assignDecl->get_statements()->get_kids() ) );
 					} // if
 				} // if
@@ -753,5 +771,68 @@
 	}
 
-	Declaration *makeUnionAssignment( UnionDecl *aggregateDecl, UnionInstType *refType, unsigned int functionNesting ) {
+	void makeStructCtorDtor( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) {
+		FunctionType *ctorType = new FunctionType( Type::Qualifiers(), false );
+
+		// Make function polymorphic in same parameters as generic struct, if applicable
+		bool isGeneric = false;  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for union)
+		std::list< TypeDecl* >& genericParams = aggregateDecl->get_parameters();
+		std::list< Expression* > structParams;  // List of matching parameters to put on types
+		for ( std::list< TypeDecl* >::const_iterator param = genericParams.begin(); param != genericParams.end(); ++param ) {
+			isGeneric = true;
+			TypeDecl *typeParam = (*param)->clone();
+			ctorType->get_forall().push_back( typeParam );
+			structParams.push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeParam->get_name(), typeParam ) ) );
+		}
+
+		ObjectDecl *thisParam = new ObjectDecl( "_this", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, structParams ) ), 0 );
+		ctorType->get_parameters().push_back( thisParam );
+
+		// Routines at global scope marked "static" to prevent multiple definitions is separate translation units
+		// because each unit generates copies of the default routines for each aggregate.
+		FunctionDecl *ctorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, ctorType, 0, true, false );
+		FunctionDecl *copyCtorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, ctorType->clone(), 0, true, false );
+		FunctionDecl *dtorDecl = new FunctionDecl( "^?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, ctorType->clone(), 0, true, false );
+		ctorDecl->fixUniqueId();
+		copyCtorDecl->fixUniqueId();
+		dtorDecl->fixUniqueId();
+
+		// add definitions
+		// TODO: add in calls to default constructors and destructors for fields
+		ctorDecl->set_statements( new CompoundStmt( noLabels ) );
+		copyCtorDecl->set_statements( new CompoundStmt( noLabels ) );
+		dtorDecl->set_statements( new CompoundStmt( noLabels ) );
+		declsToAdd.push_back( ctorDecl );
+		declsToAdd.push_back( copyCtorDecl );
+		declsToAdd.push_back( dtorDecl );
+
+		ObjectDecl * srcParam = new ObjectDecl( "_other", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, structParams ), 0 );
+		copyCtorDecl->get_functionType()->get_parameters().push_back( srcParam );
+		for ( std::list< Declaration * >::const_iterator member = aggregateDecl->get_members().begin(); member != aggregateDecl->get_members().end(); ++member ) {
+			if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( *member ) ) {
+				// query the type qualifiers of this field and skip assigning it if it is marked const.
+				// If it is an array type, we need to strip off the array layers to find its qualifiers.
+				Type * type = dwt->get_type();
+				while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
+					type = at->get_base();
+				}
+
+				if ( type->get_qualifiers().isConst ) {
+					// don't assign const members
+					continue;
+				}
+
+				if ( ArrayType *array = dynamic_cast< ArrayType * >( dwt->get_type() ) ) {
+					makeArrayFunction( srcParam, thisParam, dwt, array, "?{}", back_inserter( copyCtorDecl->get_statements()->get_kids() ) );
+					// if ( isGeneric ) makeArrayFunction( srcParam, returnVal, dwt, array, back_inserter( copyCtorDecl->get_statements()->get_kids() ) );
+				} else {
+					makeScalarFunction( srcParam, thisParam, dwt, "?{}", back_inserter( copyCtorDecl->get_statements()->get_kids() ) );
+					// if ( isGeneric ) makeScalarCtor( srcParam, returnVal, dwt, back_inserter( copyCtorDecl->get_statements()->get_kids() ) );
+				} // if
+			} // if
+		} // for
+		// if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+	}
+
+	void makeUnionFunctions( UnionDecl *aggregateDecl, UnionInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) {
 		FunctionType *assignType = new FunctionType( Type::Qualifiers(), false );
 
@@ -767,24 +848,45 @@
 		}
 
+		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, unionParams ) ), 0 );
+		assignType->get_parameters().push_back( dstParam );
+
+		// default ctor/dtor need only first parameter
+		FunctionType * ctorType = assignType->clone();
+		FunctionType * dtorType = assignType->clone();
+
+		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 );
+		assignType->get_parameters().push_back( srcParam );
+
+		// copy ctor needs both parameters
+		FunctionType * copyCtorType = assignType->clone();
+
+		// assignment needs both and return value
 		ObjectDecl *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 );
 		assignType->get_returnVals().push_back( returnVal );
-
-		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, unionParams ) ), 0 );
-		assignType->get_parameters().push_back( dstParam );
-
-		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 );
-		assignType->get_parameters().push_back( srcParam );
 
 		// Routines at global scope marked "static" to prevent multiple definitions is separate translation units
 		// because each unit generates copies of the default routines for each aggregate.
 		FunctionDecl *assignDecl = new FunctionDecl( "?=?",  functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, assignType, new CompoundStmt( noLabels ), true, false );
+		FunctionDecl *ctorDecl = new FunctionDecl( "?{}",  functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, ctorType, new CompoundStmt( noLabels ), true, false );
+		FunctionDecl *copyCtorDecl = new FunctionDecl( "?{}",  functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, copyCtorType, NULL, true, false );
+		FunctionDecl *dtorDecl = new FunctionDecl( "^?{}",  functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, dtorType, new CompoundStmt( noLabels ), true, false );
+
 		assignDecl->fixUniqueId();
+		ctorDecl->fixUniqueId();
+		copyCtorDecl->fixUniqueId();
+		dtorDecl->fixUniqueId();
 
 		makeUnionFieldsAssignment( srcParam, dstParam, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) );
 		if ( isGeneric ) makeUnionFieldsAssignment( srcParam, returnVal, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) );
-		
+
 		if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
 
-		return assignDecl;
+		// body of assignment and copy ctor is the same
+		copyCtorDecl->set_statements( assignDecl->get_statements()->clone() );
+
+		declsToAdd.push_back( assignDecl );
+		declsToAdd.push_back( ctorDecl );
+		declsToAdd.push_back( copyCtorDecl );
+		declsToAdd.push_back( dtorDecl );
 	}
 
@@ -802,5 +904,7 @@
 			StructInstType structInst( Type::Qualifiers(), structDecl->get_name() );
 			structInst.set_baseStruct( structDecl );
+
 			declsToAdd.push_back( makeStructAssignment( structDecl, &structInst, functionNesting ) );
+			makeStructCtorDtor( structDecl, &structInst, functionNesting, declsToAdd );
 			structsDone.insert( structDecl->get_name() );
 		} // if
@@ -811,5 +915,5 @@
 			UnionInstType unionInst( Type::Qualifiers(), unionDecl->get_name() );
 			unionInst.set_baseUnion( unionDecl );
-			declsToAdd.push_back( makeUnionAssignment( unionDecl, &unionInst, functionNesting ) );
+			makeUnionFunctions( unionDecl, &unionInst, functionNesting, declsToAdd );
 		} // if
 	}
@@ -1080,4 +1184,36 @@
 	}
 
+	void VerifyCtorDtor::verify( std::list< Declaration * > & translationUnit ) {
+		VerifyCtorDtor verifier;
+		acceptAll( translationUnit, verifier );
+	}
+
+	void VerifyCtorDtor::visit( FunctionDecl * funcDecl ) {
+		FunctionType * funcType = funcDecl->get_functionType();
+		std::list< DeclarationWithType * > &returnVals = funcType->get_returnVals();
+		std::list< DeclarationWithType * > &params = funcType->get_parameters();
+
+		if ( funcDecl->get_name() == "?{}" || funcDecl->get_name() == "^?{}" ) {
+			if ( params.size() == 0 ) {
+				throw SemanticError( "Constructors and destructors require at least one parameter ", funcDecl );
+			}
+			if ( ! dynamic_cast< PointerType * >( params.front()->get_type() ) ) {
+				throw SemanticError( "First parameter of a constructor or destructor must be a pointer ", funcDecl );
+			}
+			if ( returnVals.size() != 0 ) {
+				throw SemanticError( "Constructors and destructors cannot have explicit return values ", funcDecl );
+			}
+		}
+
+		Visitor::visit( funcDecl );
+		// original idea: modify signature of ctor/dtors and insert appropriate return statements
+		// to cause desired behaviour
+		// new idea: add comma exprs to every ctor call to produce first parameter.
+		// this requires some memoization of the first parameter, because it can be a
+		// complicated expression with side effects (see: malloc). idea: add temporary variable
+		// that is assigned address of constructed object in ctor argument position and
+		// return the temporary. It should also be done after all implicit ctors are
+		// added, so not in this pass!
+	}
 } // namespace SymTab
 
