Index: src/CodeTools/TrackLoc.cc
===================================================================
--- src/CodeTools/TrackLoc.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/CodeTools/TrackLoc.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -64,5 +64,5 @@
 				}
 				else {
-					assertf( false, "Top level node has no CodeLocation %s", name.c_str() );
+					assertf( false, "Top level node has no CodeLocation %s", toString( node ).c_str() );
 				}
 			}
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/InitTweak/FixInit.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// FixInit.h --
+// FixInit.cc --
 //
 // Author           : Rob Schluntz
@@ -365,5 +365,6 @@
 			// arrays are not copy constructed, so this should always be an ExprStmt
 			ImplicitCtorDtorStmt * stmt = genCtorDtor( fname, var, cpArg );
-			ExprStmt * exprStmt = strict_dynamic_cast< ExprStmt * >( stmt->get_callStmt() );
+			assertf( stmt, "ResolveCopyCtors: genCtorDtor returned nullptr: %s / %s / %s", fname.c_str(), toString( var ).c_str(), toString( cpArg ).c_str() );
+			ExprStmt * exprStmt = strict_dynamic_cast< ExprStmt * >( stmt->callStmt );
 			Expression * resolved = exprStmt->expr;
 			exprStmt->expr = nullptr; // take ownership of expr
@@ -382,4 +383,8 @@
 			} // if
 			delete stmt;
+			if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
+				// fix newly generated StmtExpr
+				postvisit( assign->stmtExpr );
+			}
 			return resolved;
 		}
@@ -475,19 +480,24 @@
 				static UniqueName retNamer("_tmp_stmtexpr_ret");
 
-				// create variable that will hold the result of the stmt expr
 				result = result->clone();
 				env->apply( result );
+				if ( ! InitTweak::isConstructable( result ) ) {
+					delete result;
+					return;
+				}
+
+				// create variable that will hold the result of the stmt expr
 				ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
-				ret->get_type()->set_const( false );
-				stmtExpr->get_returnDecls().push_front( ret );
+				ret->type->set_const( false );
+				stmtExpr->returnDecls.push_front( ret );
 
 				// must have a non-empty body, otherwise it wouldn't have a result
-				CompoundStmt * body = stmtExpr->get_statements();
+				CompoundStmt * body = stmtExpr->statements;
 				assert( ! body->get_kids().empty() );
 				// must be an ExprStmt, otherwise it wouldn't have a result
 				ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->get_kids().back() );
-				last->set_expr( makeCtorDtor( "?{}", ret, last->get_expr() ) );
-
-				stmtExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
+				last->expr = makeCtorDtor( "?{}", ret, last->get_expr() );
+
+				stmtExpr->dtors.push_front( makeCtorDtor( "^?{}", ret ) );
 			} // if
 		}
@@ -590,27 +600,30 @@
 			// to the outer context, rather than inside of the statement expression.
 			visit_children = false;
-			std::list< Statement * > & stmts = stmtExpr->get_statements()->get_kids();
+			std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
 			for ( Statement *& stmt : stmts ) {
 				stmt = stmt->acceptMutator( *visitor );
 			} // for
-			assert( stmtExpr->get_result() );
-			Type * result = stmtExpr->get_result();
+			assert( stmtExpr->result );
+			Type * result = stmtExpr->result;
 			if ( ! result->isVoid() ) {
-				for ( ObjectDecl * obj : stmtExpr->get_returnDecls() ) {
+				for ( ObjectDecl * obj : stmtExpr->returnDecls ) {
 					stmtsToAddBefore.push_back( new DeclStmt( obj ) );
 				} // for
 				// add destructors after current statement
-				for ( Expression * dtor : stmtExpr->get_dtors() ) {
+				for ( Expression * dtor : stmtExpr->dtors ) {
 					stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
 				} // for
 				// must have a non-empty body, otherwise it wouldn't have a result
 				assert( ! stmts.empty() );
-				assert( ! stmtExpr->get_returnDecls().empty() );
-				stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->get_returnDecls().front() ) ) );
-				stmtExpr->get_returnDecls().clear();
-				stmtExpr->get_dtors().clear();
-			}
-			assert( stmtExpr->get_returnDecls().empty() );
-			assert( stmtExpr->get_dtors().empty() );
+				assertf( ! stmtExpr->returnDecls.empty() || stmtExpr->dtors.empty(), "StmtExpr returns non-void, but no return decls: %s", toString( stmtExpr ).c_str() );
+				// if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
+				if ( ! stmtExpr->returnDecls.empty() ) {
+					stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->returnDecls.front() ) ) );
+				}
+				stmtExpr->returnDecls.clear();
+				stmtExpr->dtors.clear();
+			}
+			assert( stmtExpr->returnDecls.empty() );
+			assert( stmtExpr->dtors.empty() );
 		}
 
Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/InitTweak/GenInit.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -30,4 +30,5 @@
 #include "InitTweak.h"             // for isConstExpr, InitExpander, checkIn...
 #include "Parser/LinkageSpec.h"    // for isOverridable, C
+#include "ResolvExpr/Resolver.h"
 #include "SymTab/Autogen.h"        // for genImplicitCall, SizeType
 #include "SymTab/Mangler.h"        // for Mangler
@@ -89,5 +90,5 @@
 	};
 
-	struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards {
+	struct HoistArrayDimension final : public WithDeclsToAdd, public WithShortCircuiting, public WithGuards, public WithIndexer {
 		/// hoist dimension from array types in object declaration so that it uses a single
 		/// const variable of type size_t, so that side effecting array dimensions are only
@@ -104,4 +105,7 @@
 		void premutate( FunctionType * ) { visit_children = false; }
 
+		// need this so that enumerators are added to the indexer, due to premutate(AggregateDecl *)
+		void premutate( EnumDecl * ) {}
+
 		void hoist( Type * type );
 
@@ -135,5 +139,7 @@
 				if ( varExpr->var == retVal ) return;
 			}
-			stmtsToAddBefore.push_back( genCtorDtor( "?{}", retVal, returnStmt->get_expr() ) );
+			Statement * stmt = genCtorDtor( "?{}", retVal, returnStmt->expr );
+			assertf( stmt, "ReturnFixer: genCtorDtor returned nullptr: %s / %s", toString( retVal ).c_str(), toString( returnStmt->expr ).c_str() );
+			stmtsToAddBefore.push_back( stmt );
 
 			// return the retVal object
@@ -178,4 +184,6 @@
 			if ( ! arrayType->get_dimension() ) return; // xxx - recursive call to hoist?
 
+			// need to resolve array dimensions in order to accurately determine if constexpr
+			ResolvExpr::findSingleExpression( arrayType->dimension, SymTab::SizeType->clone(), indexer );
 			// don't need to hoist dimension if it's a constexpr - only need to if there's potential for side effects.
 			if ( isConstExpr( arrayType->get_dimension() ) ) return;
@@ -194,4 +202,5 @@
 	void HoistArrayDimension::premutate( FunctionDecl * ) {
 		GuardValue( inFunction );
+		inFunction = true;
 	}
 
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/InitTweak/InitTweak.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -564,4 +564,17 @@
 		void previsit( ConstantExpr * ) {}
 
+		void previsit( VariableExpr * varExpr ) {
+			visit_children = false;
+
+			if ( EnumInstType * inst = dynamic_cast< EnumInstType * >( varExpr->result ) ) {
+				long long int value;
+				if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
+					// enumerators are const expr
+					return;
+				}
+			}
+			isConstExpr = false;
+		}
+
 		bool isConstExpr = true;
 	};
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/Parser/DeclarationNode.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -343,4 +343,10 @@
 	DeclarationNode * newnode = new DeclarationNode;
 	newnode->type = new TypeData( kind == OperKinds::PointTo ? TypeData::Pointer : TypeData::Reference );
+	if ( kind == OperKinds::And ) {
+		// T && is parsed as 'And' operator rather than two references => add a second reference type
+		TypeData * td = new TypeData( TypeData::Reference );
+		td->base = newnode->type;
+		newnode->type = td;
+	}
 	if ( qualifiers ) {
 		return newnode->addQualifiers( qualifiers );
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/ResolvExpr/CommonType.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -91,13 +91,21 @@
 			// special case where one type has a reference depth of 1 larger than the other
 			if ( diff > 0 || diff < 0 ) {
+				// std::cerr << "reference depth diff: " << diff << std::endl;
 				Type * result = nullptr;
-				if ( ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 ) ) {
+				ReferenceType * ref1 = dynamic_cast< ReferenceType * >( type1 );
+				ReferenceType * ref2 = dynamic_cast< ReferenceType * >( type2 );
+				if ( diff > 0 ) {
+					// deeper on the left
+					assert( ref1 );
+					result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );
+				} else {
+					// deeper on the right
+					assert( ref2 );
+					result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );
+				}
+				if ( result && ref1 ) {
 					// formal is reference, so result should be reference
-					result = handleReference( ref1->base, type2, widenFirst, widenSecond, indexer, env, openVars );
-					if ( result ) result = new ReferenceType( ref1->get_qualifiers(), result );
-				} else {
-					// formal is value, so result should be value
-					ReferenceType * ref2 = strict_dynamic_cast< ReferenceType * > ( type2 );
-					result = handleReference( type1, ref2->base, widenFirst, widenSecond, indexer, env, openVars );
+					// std::cerr << "formal is reference; result should be reference" << std::endl;
+					result = new ReferenceType( ref1->get_qualifiers(), result );
 				}
 				// std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is [" << result << "]" << std::endl;
@@ -180,5 +188,5 @@
 	}
 
-	void CommonType::visit( __attribute((unused)) VoidType *voidType ) {}
+	void CommonType::visit( VoidType * ) {}
 
 	void CommonType::visit( BasicType *basicType ) {
@@ -246,5 +254,5 @@
 	}
 
-	void CommonType::visit( __attribute((unused)) ArrayType *arrayType ) {}
+	void CommonType::visit( ArrayType * ) {}
 
 	void CommonType::visit( ReferenceType *refType ) {
@@ -283,7 +291,7 @@
 	}
 
-	void CommonType::visit( __attribute((unused)) FunctionType *functionType ) {}
-	void CommonType::visit( __attribute((unused)) StructInstType *aggregateUseType ) {}
-	void CommonType::visit( __attribute((unused)) UnionInstType *aggregateUseType ) {}
+	void CommonType::visit( FunctionType * ) {}
+	void CommonType::visit( StructInstType * ) {}
+	void CommonType::visit( UnionInstType * ) {}
 
 	void CommonType::visit( EnumInstType *enumInstType ) {
@@ -296,5 +304,5 @@
 	}
 
-	void CommonType::visit( __attribute((unused)) TraitInstType *aggregateUseType ) {
+	void CommonType::visit( TraitInstType * ) {
 	}
 
@@ -321,6 +329,6 @@
 	}
 
-	void CommonType::visit( __attribute((unused)) TupleType *tupleType ) {}
-	void CommonType::visit( __attribute((unused)) VarArgsType *varArgsType ) {}
+	void CommonType::visit( TupleType * ) {}
+	void CommonType::visit( VarArgsType * ) {}
 
 	void CommonType::visit( ZeroType *zeroType ) {
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/ResolvExpr/ConversionCost.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -92,5 +92,5 @@
 
 	Cost convertToReferenceCost( Type * src, Type * dest, int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
-		PRINT( std::cerr << "convert to reference cost... diff " << diff << std::endl; )
+		PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )
 		if ( diff > 0 ) {
 			// TODO: document this
@@ -108,6 +108,15 @@
 			if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
 				PRINT( std::cerr << "converting between references" << std::endl; )
-				if ( srcAsRef->get_base()->get_qualifiers() <= destAsRef->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( srcAsRef->get_base(), destAsRef->get_base(), indexer, env ) ) {
-					return Cost::safe;
+				Type::Qualifiers tq1 = srcAsRef->get_base()->get_qualifiers();
+				Type::Qualifiers tq2 = destAsRef->get_base()->get_qualifiers();
+				if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->get_base(), destAsRef->get_base(), indexer, env ) ) {
+					PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
+					if ( tq1 == tq2 ) {
+						// types are the same
+						return Cost::zero;
+					} else {
+						// types are the same, except otherPointer has more qualifiers
+						return Cost::safe;
+					}
 				} else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
 					int assignResult = func( srcAsRef->get_base(), destAsRef->get_base(), env, indexer );
@@ -248,5 +257,5 @@
 	};
 
-	void ConversionCost::visit( __attribute((unused)) VoidType *voidType ) {
+	void ConversionCost::visit( VoidType * ) {
 		cost = Cost::infinity;
 	}
@@ -271,8 +280,9 @@
 	void ConversionCost::visit( PointerType * pointerType ) {
 		if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
-			PRINT( std::cerr << pointerType << " ===> " << destAsPtr; )
+			PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )
 			Type::Qualifiers tq1 = pointerType->get_base()->get_qualifiers();
 			Type::Qualifiers tq2 = destAsPtr->get_base()->get_qualifiers();
 			if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
+				PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
 				if ( tq1 == tq2 ) {
 					// types are the same
@@ -280,12 +290,16 @@
 				} else {
 					// types are the same, except otherPointer has more qualifiers
-					PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
 					cost = Cost::safe;
 				}
-			} else {  // xxx - this discards qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
+			} else {
 				int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );
 				PRINT( std::cerr << " :: " << assignResult << std::endl; )
-				if ( assignResult > 0 && pointerType->get_base()->get_qualifiers() <= destAsPtr->get_qualifiers() ) {
-					cost = Cost::safe;
+				if ( assignResult > 0 && tq1 <= tq2 ) {
+					// xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct?
+					if ( tq1 == tq2 ) {
+						cost = Cost::safe;
+					} else if ( tq1 < tq2 ) {
+						cost = Cost::safe+Cost::safe;
+					}
 				} else if ( assignResult < 0 ) {
 					cost = Cost::unsafe;
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/ResolvExpr/CurrentObject.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -38,20 +38,4 @@
 
 namespace ResolvExpr {
-	long long int getConstValue( ConstantExpr * constExpr ) {
-		if ( BasicType * basicType = dynamic_cast< BasicType * >( constExpr->get_result() ) ) {
-			if ( basicType->isInteger() ) {
-				return constExpr->get_constant()->get_ival();
-			} else {
-				assertf( false, "Non-integer constant expression in getConstValue %s", toString( constExpr ).c_str() ); // xxx - might be semantic error
-			}
-		} else if ( dynamic_cast< OneType * >( constExpr->get_result() ) ) {
-			return 1;
-		} else if ( dynamic_cast< ZeroType * >( constExpr->get_result() ) ) {
-			return 0;
-		} else {
-			assertf( false, "unhandled type on getConstValue %s", toString( constExpr->get_result() ).c_str() ); // xxx - might be semantic error
-		}
-	}
-
 	template< typename AggrInst >
 	TypeSubstitution makeGenericSubstitution( AggrInst * inst ) {
@@ -151,8 +135,17 @@
 		void setSize( Expression * expr ) {
 			if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
-				size = getConstValue( constExpr );
+				size = constExpr->intValue();
+				isVLA = false;
 				PRINT( std::cerr << "array type with size: " << size << std::endl; )
 			}	else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
 				setSize( castExpr->get_arg() ); // xxx - need to perform the conversion specified by the cast
+			} else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
+				if ( EnumInstType * inst = dynamic_cast< EnumInstType * > ( varExpr->result ) ) {
+					long long int value;
+					if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
+						size = value;
+						isVLA = false;
+					}
+				}
 			} else {
 				assertf( false, "unhandled expression in setSize: %s", toString( expr ).c_str() ); // xxx - if not a constant expression, it's not simple to determine how long the array actually is, which is necessary for initialization to be done correctly -- fix this
@@ -164,10 +157,14 @@
 			// need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions
 			if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
-				index = getConstValue( constExpr );
+				index = constExpr->intValue();
 			} else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
 				setPosition( castExpr->get_arg() );
 			} else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
-				assertf( dynamic_cast<EnumInstType *> ( varExpr->get_result() ), "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );
-				index = 0; // xxx - get actual value of enum constant
+				EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );
+				assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );
+				long long int value;
+				if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
+					index = value;
+				}
 			} else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {
 				index = 0; // xxx - get actual sizeof/alignof value?
@@ -189,5 +186,5 @@
 		}
 
-		virtual operator bool() const { return index < size; }
+		virtual operator bool() const { return ! isVLA && index < size; }
 
 		virtual MemberIterator & bigStep() {
@@ -195,5 +192,5 @@
 			++index;
 			delete memberIter;
-			if ( index < size ) memberIter = createMemberIterator( base );
+			if ( ! isVLA && index < size ) memberIter = createMemberIterator( base );
 			else memberIter = nullptr;
 			return *this;
@@ -242,4 +239,5 @@
 		size_t index = 0;
 		size_t size = 0;
+		bool isVLA = true;
 		MemberIterator * memberIter = nullptr;
 	};
Index: src/ResolvExpr/FindOpenVars.cc
===================================================================
--- src/ResolvExpr/FindOpenVars.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/ResolvExpr/FindOpenVars.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -19,18 +19,16 @@
 #include <map>                    // for map<>::mapped_type
 
+#include "Common/PassVisitor.h"
 #include "SynTree/Declaration.h"  // for TypeDecl, DeclarationWithType (ptr ...
 #include "SynTree/Type.h"         // for Type, Type::ForallList, ArrayType
-#include "SynTree/Visitor.h"      // for Visitor
 
 namespace ResolvExpr {
-	class FindOpenVars : public Visitor {
-	  public:
+	struct FindOpenVars : public WithGuards {
 		FindOpenVars( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
 
-	  private:
-		virtual void visit(PointerType *pointerType);
-		virtual void visit(ArrayType *arrayType);
-		virtual void visit(FunctionType *functionType);
-		virtual void visit(TupleType *tupleType);
+		void previsit( PointerType * pointerType );
+		void previsit( ArrayType * arrayType );
+		void previsit( FunctionType * functionType );
+		void previsit( TupleType * tupleType );
 
 		void common_action( Type *type );
@@ -42,5 +40,5 @@
 
 	void findOpenVars( Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {
-		FindOpenVars finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );
+		PassVisitor<FindOpenVars> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );
 		type->accept( finder );
 	}
@@ -70,32 +68,28 @@
 			} // for
 		} // if
-///   std::cout << "type is ";
-///   type->print( std::cout );
-///   std::cout << std::endl << "need is" << std::endl;
-///   printAssertionSet( needAssertions, std::cout );
-///   std::cout << std::endl << "have is" << std::endl;
-///   printAssertionSet( haveAssertions, std::cout );
+///   std::cerr << "type is ";
+///   type->print( std::cerr );
+///   std::cerr << std::endl << "need is" << std::endl;
+///   printAssertionSet( needAssertions, std::cerr );
+///   std::cerr << std::endl << "have is" << std::endl;
+///   printAssertionSet( haveAssertions, std::cerr );
 	}
 
-	void FindOpenVars::visit(PointerType *pointerType) {
+	void FindOpenVars::previsit(PointerType *pointerType) {
 		common_action( pointerType );
-		Visitor::visit( pointerType );
 	}
 
-	void FindOpenVars::visit(ArrayType *arrayType) {
+	void FindOpenVars::previsit(ArrayType *arrayType) {
 		common_action( arrayType );
-		Visitor::visit( arrayType );
 	}
 
-	void FindOpenVars::visit(FunctionType *functionType) {
+	void FindOpenVars::previsit(FunctionType *functionType) {
 		common_action( functionType );
 		nextIsOpen = ! nextIsOpen;
-		Visitor::visit( functionType );
-		nextIsOpen = ! nextIsOpen;
+		GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
 	}
 
-	void FindOpenVars::visit(TupleType *tupleType) {
+	void FindOpenVars::previsit(TupleType *tupleType) {
 		common_action( tupleType );
-		Visitor::visit( tupleType );
 	}
 } // namespace ResolvExpr
Index: src/ResolvExpr/Occurs.cc
===================================================================
--- src/ResolvExpr/Occurs.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/ResolvExpr/Occurs.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Occurs.cc -- 
+// Occurs.cc --
 //
 // Author           : Richard C. Bilson
@@ -17,29 +17,27 @@
 #include <string>             // for string
 
+#include "Common/PassVisitor.h"
 #include "SynTree/Type.h"     // for TypeInstType, Type
-#include "SynTree/Visitor.h"  // for Visitor
 #include "TypeEnvironment.h"  // for EqvClass, TypeEnvironment
 
 namespace ResolvExpr {
-	class Occurs : public Visitor {
-	  public:
+	struct Occurs : public WithVisitorRef<Occurs> {
 		Occurs( std::string varName, const TypeEnvironment &env );
-		bool get_result() const { return result; }
-		virtual void visit( TypeInstType *typeInst );
-	  private:
+		void previsit( TypeInstType * typeInst );
+
 		bool result;
 		std::set< std::string > eqvVars;
-		const TypeEnvironment &env;
+		const TypeEnvironment &tenv;
 	};
 
 	bool occurs( Type *type, std::string varName, const TypeEnvironment &env ) {
-		Occurs occur( varName, env );
+		PassVisitor<Occurs> occur( varName, env );
 		type->accept( occur );
-		return occur.get_result();
+		return occur.pass.result;
 	}
 
-	Occurs::Occurs( std::string varName, const TypeEnvironment &env ) : result( false ), env( env ) {
+	Occurs::Occurs( std::string varName, const TypeEnvironment & env ) : result( false ), tenv( env ) {
 		EqvClass eqvClass;
-		if ( env.lookup( varName, eqvClass ) ) {
+		if ( tenv.lookup( varName, eqvClass ) ) {
 			eqvVars = eqvClass.vars;
 		} else {
@@ -48,17 +46,17 @@
 	}
 
-	void Occurs::visit( TypeInstType *typeInst ) {
+	void Occurs::previsit( TypeInstType * typeInst ) {
 		EqvClass eqvClass;
-///   std::cout << "searching for vars: ";
-///   std::copy( eqvVars.begin(), eqvVars.end(), std::ostream_iterator< std::string >( std::cout, " " ) );
-///   std::cout << std::endl;
+///   std::cerr << "searching for vars: ";
+///   std::copy( eqvVars.begin(), eqvVars.end(), std::ostream_iterator< std::string >( std::cerr, " " ) );
+///   std::cerr << std::endl;
 		if ( eqvVars.find( typeInst->get_name() ) != eqvVars.end() ) {
 			result = true;
-		} else if ( env.lookup( typeInst->get_name(), eqvClass ) ) {
+		} else if ( tenv.lookup( typeInst->get_name(), eqvClass ) ) {
 			if ( eqvClass.type ) {
-///       std::cout << typeInst->get_name() << " is bound to";
-///       eqvClass.type->print( std::cout );
-///       std::cout << std::endl;
-				eqvClass.type->accept( *this );
+///       std::cerr << typeInst->get_name() << " is bound to";
+///       eqvClass.type->print( std::cerr );
+///       std::cerr << std::endl;
+				eqvClass.type->accept( *visitor );
 			} // if
 		} // if
Index: src/ResolvExpr/PolyCost.cc
===================================================================
--- src/ResolvExpr/PolyCost.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/ResolvExpr/PolyCost.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -14,33 +14,31 @@
 //
 
+#include "Common/PassVisitor.h"
 #include "SymTab/Indexer.h"   // for Indexer
 #include "SynTree/Type.h"     // for TypeInstType, Type
-#include "SynTree/Visitor.h"  // for Visitor
 #include "TypeEnvironment.h"  // for EqvClass, TypeEnvironment
 
 namespace ResolvExpr {
-	class PolyCost : public Visitor {
-	  public:
+	struct PolyCost {
 		PolyCost( const TypeEnvironment &env, const SymTab::Indexer &indexer );
-		int get_result() const { return result; }
-	  private:
-		virtual void visit(TypeInstType *aggregateUseType);
+
+		void previsit( TypeInstType * aggregateUseType );
 		int result;
-		const TypeEnvironment &env;
+		const TypeEnvironment &tenv;
 		const SymTab::Indexer &indexer;
 	};
 
 	int polyCost( Type *type, const TypeEnvironment & env, const SymTab::Indexer &indexer ) {
-		PolyCost coster( env, indexer );
+		PassVisitor<PolyCost> coster( env, indexer );
 		type->accept( coster );
-		return coster.get_result();
+		return coster.pass.result;
 	}
 
-	PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), env( env ), indexer( indexer ) {
+	PolyCost::PolyCost( const TypeEnvironment & env, const SymTab::Indexer & indexer ) : result( 0 ), tenv( env ), indexer( indexer ) {
 	}
 
-	void PolyCost::visit(TypeInstType * typeInst) {
+	void PolyCost::previsit(TypeInstType * typeInst) {
 		EqvClass eqvClass;
-		if ( env.lookup( typeInst->name, eqvClass ) ) {
+		if ( tenv.lookup( typeInst->name, eqvClass ) ) {
 			if ( eqvClass.type ) {
 				if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass.type ) ) {
Index: src/ResolvExpr/PtrsAssignable.cc
===================================================================
--- src/ResolvExpr/PtrsAssignable.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/ResolvExpr/PtrsAssignable.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -67,5 +67,5 @@
 	PtrsAssignable::PtrsAssignable( Type *dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}
 
-	void PtrsAssignable::visit( __attribute((unused)) VoidType *voidType ) {
+	void PtrsAssignable::visit( VoidType * ) {
 		// T * = void * is disallowed - this is a change from C, where any
 		// void * can be assigned or passed to a non-void pointer without a cast.
Index: src/ResolvExpr/Resolver.h
===================================================================
--- src/ResolvExpr/Resolver.h	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/ResolvExpr/Resolver.h	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -33,4 +33,5 @@
 	void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer );
 	void findSingleExpression( Expression *& untyped, const SymTab::Indexer &indexer );
+	void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer &indexer );
 	void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer );
 	void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer );
Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/SymTab/Indexer.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -572,4 +572,20 @@
 	}
 
+	void Indexer::addMembers( AggregateDecl * aggr, Expression * expr ) {
+		for ( Declaration * decl : aggr->members ) {
+			if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
+				addId( dwt, expr );
+				if ( dwt->name == "" ) {
+					Type * t = dwt->get_type()->stripReferences();
+					if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
+						Expression * base = expr->clone();
+						ResolvExpr::referenceToRvalueConversion( base );
+						addMembers( t->getAggr(), new MemberExpr( dwt, base ) );
+					}
+				}
+			}
+		}
+	}
+
 	void Indexer::addWith( WithStmt * stmt ) {
 		for ( Expression * expr : stmt->exprs ) {
@@ -578,9 +594,5 @@
 				assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
 
-				for ( Declaration * decl : aggr->members ) {
-					if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
-						addId( dwt, expr );
-					}
-				}
+				addMembers( aggr, expr );
 			}
 		}
Index: src/SymTab/Indexer.h
===================================================================
--- src/SymTab/Indexer.h	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/SymTab/Indexer.h	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -86,4 +86,7 @@
 		void addWith( WithStmt * );
 
+		/// adds all of the members of the Aggregate (addWith helper)
+		void addMembers( AggregateDecl * aggr, Expression * expr );
+
 		/// convenience function for adding a list of Ids to the indexer
 		void addIds( const std::list< DeclarationWithType * > & decls );
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/SymTab/Validate.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -94,5 +94,5 @@
 		template< typename AggDecl > void handleAggregate( AggDecl *aggregateDecl );
 
-		bool inStruct = false;
+		AggregateDecl * parentAggr = nullptr;
 	};
 
@@ -303,10 +303,10 @@
 	template< typename AggDecl >
 	void HoistStruct::handleAggregate( AggDecl *aggregateDecl ) {
-		if ( inStruct ) {
+		if ( parentAggr ) {
 			// Add elements in stack order corresponding to nesting structure.
 			declsToAddBefore.push_front( aggregateDecl );
 		} else {
-			GuardValue( inStruct );
-			inStruct = true;
+			GuardValue( parentAggr );
+			parentAggr = aggregateDecl;
 		} // if
 		// Always remove the hoisted aggregate from the inner structure.
Index: src/SynTree/AggregateDecl.cc
===================================================================
--- src/SynTree/AggregateDecl.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/SynTree/AggregateDecl.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -86,4 +86,37 @@
 std::string TraitDecl::typeString() const { return "trait"; }
 
+namespace {
+	long long int getConstValue( Expression * expr ) {
+		if ( CastExpr * castExpr = dynamic_cast< CastExpr * > ( expr ) ) {
+			return getConstValue( castExpr->arg );
+		} else if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
+			return constExpr->intValue();
+		} else {
+			assertf( false, "Unhandled expression type in getConstValue for enumerators: %s", toString( expr ).c_str() );
+		}
+	}
+}
+
+bool EnumDecl::valueOf( Declaration * enumerator, long long int & value ) {
+	if ( enumValues.empty() ) {
+		long long int currentValue = 0;
+		for ( Declaration * member : members ) {
+			ObjectDecl * field = strict_dynamic_cast< ObjectDecl * >( member );
+			if ( field->init ) {
+				SingleInit * init = strict_dynamic_cast< SingleInit * >( field->init );
+				currentValue = getConstValue( init->value );
+			}
+			assertf( enumValues.count( field->name ) == 0, "Enum %s has multiple members with the name %s", name.c_str(), field->name.c_str() );
+			enumValues[ field->name ] = currentValue;
+			++currentValue;
+		}
+	}
+	if ( enumValues.count( enumerator->name ) ) {
+		value = enumValues[ enumerator->name ];
+		return true;
+	}
+	return false;
+}
+
 // Local Variables: //
 // tab-width: 4 //
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/SynTree/Declaration.h	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -319,8 +319,11 @@
 	EnumDecl( const EnumDecl &other ) : Parent( other ) {}
 
+	bool valueOf( Declaration * enumerator, long long int & value );
+
 	virtual EnumDecl *clone() const override { return new EnumDecl( *this ); }
 	virtual void accept( Visitor &v ) override { v.visit( this ); }
 	virtual Declaration *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
   private:
+	std::map< std::string, long long int > enumValues;
 	virtual std::string typeString() const override;
 };
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/SynTree/Expression.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -83,4 +83,17 @@
 }
 
+long long int ConstantExpr::intValue() const {
+	if ( BasicType * basicType = dynamic_cast< BasicType * >( result ) ) {
+		if ( basicType->isInteger() ) {
+			return get_constant()->get_ival();
+		}
+	} else if ( dynamic_cast< OneType * >( result ) ) {
+		return 1;
+	} else if ( dynamic_cast< ZeroType * >( result ) ) {
+		return 0;
+	}
+	throw SemanticError( "Constant expression of non-integral type ", this );
+}
+
 VariableExpr::VariableExpr( DeclarationWithType *_var ) : Expression(), var( _var ) {
 	assert( var );
@@ -589,10 +602,10 @@
 	if ( ! body.empty() ) {
 		if ( ExprStmt * exprStmt = dynamic_cast< ExprStmt * >( body.back() ) ) {
-			set_result( maybeClone( exprStmt->get_expr()->get_result() ) );
+			result = maybeClone( exprStmt->expr->result );
 		}
 	}
 	// ensure that StmtExpr has a result type
 	if ( ! result ) {
-		set_result( new VoidType( Type::Qualifiers() ) );
+		result = new VoidType( Type::Qualifiers() );
 	}
 }
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/SynTree/Expression.h	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -295,5 +295,8 @@
 
 	Constant * get_constant() { return & constant; }
+	const Constant * get_constant() const { return & constant; }
 	void set_constant( const Constant & newValue ) { constant = newValue; }
+
+	long long int intValue() const;
 
 	virtual ConstantExpr * clone() const { return new ConstantExpr( * this ); }
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/Tuples/TupleAssignment.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -272,5 +272,11 @@
 		// args.push_back( new AddressExpr( new VariableExpr( left ) ) );
 		if ( right ) args.push_back( new VariableExpr( right ) );
-		return new UntypedExpr( new NameExpr( fname ), args );
+		if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
+			args.front() = new AddressExpr( args.front() );
+			if ( right ) args.back() = new AddressExpr( args.back() );
+			return new UntypedExpr( new NameExpr( "?=?" ), args );
+		} else {
+			return new UntypedExpr( new NameExpr( fname ), args );
+		}
 	}
 
@@ -291,5 +297,5 @@
 		if ( ! dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
 			ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
-			ret->set_init( ctorInit );
+			ret->init = ctorInit;
 			ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
 			PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/Tuples/TupleExpansion.cc	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -202,4 +202,5 @@
 			// generate struct type to replace tuple type based on the number of components in the tuple
 			StructDecl * decl = new StructDecl( toString( "_tuple", tupleSize, "_" ) );
+			decl->location = tupleType->location;
 			decl->set_body( true );
 			for ( size_t i = 0; i < tupleSize; ++i ) {
Index: src/libcfa/concurrency/monitor.c
===================================================================
--- src/libcfa/concurrency/monitor.c	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ src/libcfa/concurrency/monitor.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -534,5 +534,5 @@
 	__lock_size_t actual_count = aggregate( mon_storage, mask );
 
-	__cfaabi_dbg_print_buffer_decl( "Kernel : waitfor %d (s: %d, m: %d)\n", actual_count, mask.size, (__lock_size_t)max);
+	__cfaabi_dbg_print_buffer_decl( "Kernel : waitfor %"PRIdFAST16" (s: %"PRIdFAST16", m: %"PRIdFAST16")\n", actual_count, mask.size, (__lock_size_t)max);
 
 	if(actual_count == 0) return;
@@ -575,5 +575,5 @@
 				monitor_save;
 
-				__cfaabi_dbg_print_buffer_local( "Kernel :  baton of %d monitors : ", count );
+				__cfaabi_dbg_print_buffer_local( "Kernel :  baton of %"PRIdFAST16" monitors : ", count );
 				#ifdef __CFA_DEBUG_PRINT__
 					for( int i = 0; i < count; i++) {
Index: src/tests/.expect/tupleAssign.txt
===================================================================
--- src/tests/.expect/tupleAssign.txt	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,12 +1,0 @@
-u=5 v=6 x=10 y=11 z=[100, 200]
-u=5 v=6 x=10 y=11 z=[100, 200]
-u=11 v=10 x=11 y=10 z=[11, 10]
-u=11 v=10 x=11 y=10 z=[11, 10]
-u=10 v=11 z=[10, 11]
-u=10 v=11 z=[10, 11]
-u=123 v=456 z=[111, 222]
-u=123 v=456 z=[111, 222]
-d=94.12 i=94 c=^ t=[94, 94.12, 94]
-d=94.12 i=94 c=^ t=[94, 94.12, 94]
-d=-94.12 i=-94 c=¢ t=[-94, -94.12, -94]
-d=-94.12 i=-94 c=¢ t=[-94, -94.12, -94]
Index: src/tests/.expect/tupleCast.txt
===================================================================
--- src/tests/.expect/tupleCast.txt	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,6 +1,0 @@
-10 A 3.14
-10 A
-10
-10 65
-ran f
-99 F
Index: src/tests/.expect/tupleFunction.txt
===================================================================
--- src/tests/.expect/tupleFunction.txt	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,12 +1,0 @@
-foo([123, 456, 999.123, {321, 654, Q, 3.14}])
-a=123 b=456 c=999.123 d={321, 654, Q, 3.14}
-X=[123, 456, 999.123, {321, 654, Q, 3.14}]
-foo(...)=456
-bar([777, 2.76, 8675])
-bar([123, 999.123, 456])
-baz(777, 2.76, 8675)
-baz(123, 999.123, 456)
-qux([777, 2.76], 8675)
-qux([123, 999.123], 456)
-x=[3, 5.254, 4]
-x1=3 x2=5.254 x3=4
Index: src/tests/.expect/tupleMember.txt
===================================================================
--- src/tests/.expect/tupleMember.txt	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,4 +1,0 @@
-called f!
-g(...)=13.5
-v.[f1, i.[f2, f3], f4]=[12, 11, 13, 3.14159]
-v.[f1, i.[f2, f3], f4]=[4, [987, 2], 6.28]
Index: src/tests/.expect/tuplePolymorphism.txt
===================================================================
--- src/tests/.expect/tuplePolymorphism.txt	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,5 +1,0 @@
-132 1001 459
-132 1001.12 459
-123 999.123 456
-246 1998.25 912
-1.21 x 10.21 1111 v 54385938 1111 v 54385938
Index: src/tests/.expect/tupleVariadic.txt
===================================================================
--- src/tests/.expect/tupleVariadic.txt	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,18 +1,0 @@
-called ?{} with no a
-array = { }
-called ?{} with a: 999
-array = { 999, }
-called ?{} with a: 123 456
-array = { 123, 456, }
-called ?{} with a: 100 200 300
-array = { 100, 200, 300, }
-called ?{} with a: 10 2 3 4
-array = { 10, 2, 3, 4, }
-copy=111111
-calling func
-called process(int) 3
-called process(double) 2
-called process(int) 111
-called process(double) 4.145
-called func(void)
-finished func
Index: src/tests/tuple/.expect/tupleAssign.txt
===================================================================
--- src/tests/tuple/.expect/tupleAssign.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/.expect/tupleAssign.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,12 @@
+u=5 v=6 x=10 y=11 z=[100, 200]
+u=5 v=6 x=10 y=11 z=[100, 200]
+u=11 v=10 x=11 y=10 z=[11, 10]
+u=11 v=10 x=11 y=10 z=[11, 10]
+u=10 v=11 z=[10, 11]
+u=10 v=11 z=[10, 11]
+u=123 v=456 z=[111, 222]
+u=123 v=456 z=[111, 222]
+d=94.12 i=94 c=^ t=[94, 94.12, 94]
+d=94.12 i=94 c=^ t=[94, 94.12, 94]
+d=-94.12 i=-94 c=¢ t=[-94, -94.12, -94]
+d=-94.12 i=-94 c=¢ t=[-94, -94.12, -94]
Index: src/tests/tuple/.expect/tupleCast.txt
===================================================================
--- src/tests/tuple/.expect/tupleCast.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/.expect/tupleCast.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,6 @@
+10 A 3.14
+10 A
+10
+10 65
+ran f
+99 F
Index: src/tests/tuple/.expect/tupleFunction.txt
===================================================================
--- src/tests/tuple/.expect/tupleFunction.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/.expect/tupleFunction.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,12 @@
+foo([123, 456, 999.123, {321, 654, Q, 3.14}])
+a=123 b=456 c=999.123 d={321, 654, Q, 3.14}
+X=[123, 456, 999.123, {321, 654, Q, 3.14}]
+foo(...)=456
+bar([777, 2.76, 8675])
+bar([123, 999.123, 456])
+baz(777, 2.76, 8675)
+baz(123, 999.123, 456)
+qux([777, 2.76], 8675)
+qux([123, 999.123], 456)
+x=[3, 5.254, 4]
+x1=3 x2=5.254 x3=4
Index: src/tests/tuple/.expect/tupleMember.txt
===================================================================
--- src/tests/tuple/.expect/tupleMember.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/.expect/tupleMember.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,4 @@
+called f!
+g(...)=13.5
+v.[f1, i.[f2, f3], f4]=[12, 11, 13, 3.14159]
+v.[f1, i.[f2, f3], f4]=[4, [987, 2], 6.28]
Index: src/tests/tuple/.expect/tuplePolymorphism.txt
===================================================================
--- src/tests/tuple/.expect/tuplePolymorphism.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/.expect/tuplePolymorphism.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,5 @@
+132 1001 459
+132 1001.12 459
+123 999.123 456
+246 1998.25 912
+1.21 x 10.21 1111 v 54385938 1111 v 54385938
Index: src/tests/tuple/.expect/tupleVariadic.txt
===================================================================
--- src/tests/tuple/.expect/tupleVariadic.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/.expect/tupleVariadic.txt	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,18 @@
+called ?{} with no a
+array = { }
+called ?{} with a: 999
+array = { 999, }
+called ?{} with a: 123 456
+array = { 123, 456, }
+called ?{} with a: 100 200 300
+array = { 100, 200, 300, }
+called ?{} with a: 10 2 3 4
+array = { 10, 2, 3, 4, }
+copy=111111
+calling func
+called process(int) 3
+called process(double) 2
+called process(int) 111
+called process(double) 4.145
+called func(void)
+finished func
Index: src/tests/tuple/tupleAssign.c
===================================================================
--- src/tests/tuple/tupleAssign.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/tupleAssign.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,66 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tupleAssign.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Nov 15 17:24:32 2016
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon Mar  6 21:23:58 2017
+// Update Count     : 34
+//
+
+#include <fstream>
+
+int main() {
+	{
+		// test multiple assignment and cascading assignment
+		int u = 5, v = 6, x = 10, y = 11;
+		[int, int] z = [100, 200];
+
+		// swap x, y and store the new [x, y] in [u, v] and in z;
+		printf( "u=%d v=%d x=%d y=%d z=[%d, %d]\n", u, v, x, y, z );
+		sout | "u=" | u | "v=" | v | "x=" | x | "y=" | y | "z=[" | z | "]" | endl;
+		z = [u, v] = [x, y] = [y, x];
+		printf( "u=%d v=%d x=%d y=%d z=[%d, %d]\n", u, v, x, y, z );
+		sout | "u=" | u | "v=" | v | "x=" | x | "y=" | y | "z=[" | z | "]" | endl;
+
+		// shuffle elements -- v = z.0, z.0 = z.1, z.1 = u, u = v
+		[v, z, u] = [z, u, v];
+		printf( "u=%d v=%d z=[%d, %d]\n", u, v, z );
+		sout | "u=" | u | "v=" | v | "z=[" | z | "]" | endl;
+
+		// multiple assignment with tuple expression on right
+		z = [111, 222];
+		[u, v] = [123, 456];
+		printf( "u=%d v=%d z=[%d, %d]\n", u, v, z );
+		sout | "u=" | u | "v=" | v | "z=[" | z | "]" | endl;
+	}
+	{
+		// test mass assignment
+		double d = 0.0;
+		int i = 0;
+		char c = '\0';
+		struct X {
+			int z;
+		} x;
+		X ?=?(X & x, double d) {}
+		[int, double, int] t;
+
+		// no conversion from X to integral types, so this serves as a santiy
+		// check that as long as this compiles, ?=?(_, x) is not generated.
+		[t, x, d, i, c, x] = (double)94.12;
+		printf( "d=%lg i=%d c=%c t=[%d, %lg, %d]\n", d, i, (int)c, t );
+		sout | "d=" | d | "i=" | i | "c=" | c | ' ' | "t=[" | t | "]" | endl;
+		[x, c, i, d, x, t] = (double)-94.12;
+		printf( "d=%lg i=%d c=%c t=[%d, %lg, %d]\n", d, i, c, t );
+		sout | "d=" | d | "i=" | i | "c=" | c | ' ' | "t=[" | t | "]" | endl;
+	}
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: src/tests/tuple/tupleCast.c
===================================================================
--- src/tests/tuple/tupleCast.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/tupleCast.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,30 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tupleCast.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Mon Dec 12 15:56:07 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Mon Dec 12 15:56:20 2016
+// Update Count     : 2
+//
+
+[char, int, double] f() { printf("ran f\n"); return ['c', 70, 6.28]; }
+
+int main() {
+  [int, char, float] x = [10, 'A', 3.14f];
+  printf("%d %c %g\n", ([int, char, float])x);
+  printf("%d %c\n", ([int, char])x);
+  printf("%d\n", ([int])x);
+  // printf("%d\n", (int)x);
+  printf("%g %g\n", ([double, float])x);
+  printf("%d %c\n", ([int, char])f());
+}
+
+// Local Variables: //
+// tab-width: 2 //
+// End: //
Index: src/tests/tuple/tupleFunction.c
===================================================================
--- src/tests/tuple/tupleFunction.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/tupleFunction.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,98 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tupleFunction.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Nov 15 17:24:32 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Tue Nov 15 17:27:28 2016
+// Update Count     : 3
+//
+
+struct S {
+	int f1, f2;
+	char f3;
+	double f4;
+} v;
+
+[int] foo( [int, int, double, S] x ) {
+	printf("foo([%d, %d, %lg, {%d, %d, %c, %lg}])\n", x.0, x.1, x.2, x.3.[f1, f2, f3, f4]);
+	int a, b;
+	double c;
+	S d;
+	[a, b, c, d] = x;
+	[int, int, double, S] X = x;
+	printf("a=%d b=%d c=%lg d={%d, %d, %c, %lg}\n", a, b, c, d.[f1, f2, f3, f4]);
+	printf("X=[%d, %d, %lg, {%d, %d, %c, %lg}]\n", X.0, X.1, X.2, X.3.[f1, f2, f3, f4]);
+	return b;
+}
+
+[void] bar( [int, double, int] z ) {
+	printf("bar([%d, %lg, %d])\n", z);
+}
+
+[void] baz( int a, double b, int c ) {
+	printf("baz(%d, %lg, %d)\n", a, b, c);
+}
+
+[void] qux( [int, double] n, int m ) {
+	printf("qux([%d, %lg], %d)\n", n, m);
+}
+
+[int, double x, int] quux() {
+	return [3, 5.254, 4];
+}
+[[[int, double, int], [int, double]]] quuux() {
+	return [1, 2, 3, 4, 5];
+}
+
+int main() {
+	[int, double, int] x = [777, 2.76, 8675];
+	int x1 = 123, x3 = 456;
+	double x2 = 999.123;
+
+	printf("foo(...)=%d\n", foo(x1, x3, x2, (S){ 321, 654, 'Q', 3.14 }));
+
+	// call function with tuple parameter using tuple variable arg
+	bar(x);
+
+	// call function with tuple parameter using multiple values
+	bar(x1, x2, x3);
+
+	// call function with multiple parameters using tuple variable arg
+	baz(x);
+
+	// call function with multiple parameters using multiple args
+	baz(x1, x2, x3);
+
+	// call function with multiple parameters, one of which is a tuple using tuple variable arg
+	qux(x);
+
+	// call function with multiple parameters, one of which is a tuple using multiple args
+	qux(x1, x2, x3);
+
+	// call function with multiple return values and assign into a tuple variable
+	x = quux();
+	printf("x=[%d, %lg, %d]\n", x);
+
+	// call function with multiple return values and assign into a tuple expression
+	[x1, x2, x3] = quux();
+	printf("x1=%d x2=%lg x3=%d\n", x1, x2, x3);
+
+	// xxx - tuples of type parameters should come out as generic types?
+	// [x1, x2, x3] = ([(int)x1, (int)x2, (int)x3]) + ([(int)1, (int)2, (int)3]);
+	// ([(int)x1, (int)x2, (int)x3]) + ([(int)1, (int)2, (int)3]);
+	// printf("%d %g %d\n", x1, x2, x3);
+
+	// xxx - comes out the back as a cast, but should come out as a tuple expression of the first n fields cast to each of the result types
+	// ([int, double])x;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
+
Index: src/tests/tuple/tupleMember.c
===================================================================
--- src/tests/tuple/tupleMember.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/tupleMember.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,61 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tupleFunction.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Nov 15 17:24:32 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Tue Nov 15 17:27:28 2016
+// Update Count     : 3
+//
+
+void f() {
+	printf("called f!\n");
+}
+
+double g(double x, char y, int z) {
+	return z-y+x;
+}
+
+struct V2	{
+	int f2, f3;
+};
+struct V {
+	int f1;
+	V2 i; // temporary
+	// struct V2 {
+	//   int f2, f3;
+	// } i;
+	double f4;
+} v;
+
+V & h() {
+	static V local = { 111, { 222, 333 }, 444.5 };
+	return local;
+}
+
+int main() {
+	struct X {
+		int a;
+		double b;
+		char c;
+	} x = { 10, 12.5, '\x9' };
+
+	// should only call f once
+	printf("g(...)=%lg\n", g((f(), x).[b, c, a]));
+
+	v.[f1, i.[f2, f3], f4].[1.0, 2, 0, 1.1] = [11, 3.14159, 12, 13];
+
+	printf("v.[f1, i.[f2, f3], f4]=[%d, %d, %d, %lg]\n", v.[f1, i.[f2, f3], f4]);
+
+	h().[f1, i.[f2, f3], f4].[1.0, 2, 0, 1.1] = [987, 6.28, 4, 2];
+	printf("v.[f1, i.[f2, f3], f4]=[%d, [%d, %d], %lg]\n", h().[f1, i.[f2, f3], f4]);
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: src/tests/tuple/tuplePolymorphism.c
===================================================================
--- src/tests/tuple/tuplePolymorphism.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/tuplePolymorphism.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,74 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tuplePolymorphism.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Tue Nov 16 10:38:00 2016
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu May 18 18:05:12 2017
+// Update Count     : 4
+//
+
+// packed is needed so that structs are not passed with the same alignment as function arguments
+__attribute__((packed)) struct A {
+	double x;
+	char y;
+	double z;
+};
+
+__attribute__((packed)) struct B {
+	long long x;
+	char y;
+	long long z;
+};
+
+// ensure that f is a viable candidate for g, even though its parameter structure does not exactly match
+[A] f([A, B] x, B y) { printf("%g %c %g %lld %c %lld %lld %c %lld\n", x.0.[x,y,z], x.1.[x,y,z], y.[x,y,z]); return x.0; }
+forall(otype T, otype U | { T f(T, U, U); })
+void g(T x, U y) { f(x, y, y); }
+
+// add two triples
+forall(otype T | { T ?+?(T, T); })
+[T, T, T] ?+?([T, T, T] x, [T, T, T] y) {
+	return [x.0+y.0, x.1+y.1, x.2+y.2];
+}
+
+int main() {
+	int x1 = 123, x3 = 456;
+	double x2 = 999.123;
+
+	int i1 = 111, i3 = 222;
+	double i2 = 333;
+
+	int d1 = 555, d3 = 444;
+	double d2 = 666;
+
+
+	[i1, i2, i3] = ([x1, (int)x2, x3]) + ([9, 2, 3]);
+	[d1, d2, d3] = ([x1, x2, x3]) + ([9, 2, 3]);
+	printf("%d %g %d\n", i1, i2, i3);
+	printf("%d %g %d\n", d1, d2, d3);
+
+	[double, double, double] zzz;
+	zzz = [x1, x2, x3];
+	printf("%g %g %g\n", zzz);
+	[x1, x2, x3] = zzz+zzz;
+	printf("%d %g %d\n", x1, x2, x3);
+
+	// ensure non-matching assertions are specialized correctly
+	g((A){ 1.21, 'x', 10.21}, (B){ 1111LL, 'v', 54385938LL });
+}
+
+forall(otype T)
+[T, T] foo([T, T] y) {
+	[T, T] x;
+	return x;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: src/tests/tuple/tupleVariadic.c
===================================================================
--- src/tests/tuple/tupleVariadic.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/tupleVariadic.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,124 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// tuplePolymorphism.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Fri Dec 16 10:25:35 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Fri Dec 21 14:42:48 2016
+// Update Count     : 2
+//
+
+void func(void) {
+	printf("called func(void)\n");
+}
+forall(otype T, ttype Params | { void process(T); void func(Params); })
+void func(T arg1, Params p) {
+	process(arg1);
+	func(p);
+}
+void process(int x) {
+	printf("called process(int) %d\n", x);
+}
+void process(double x) {
+	printf("called process(double) %g\n", x);
+}
+
+forall( dtype T, ttype Params | sized(T) | { void ?{}(T &, Params); } )
+T * new(Params p);
+
+struct array {
+	int * data;
+	int size;
+};
+
+// xxx - eventually this will be collapsed...x
+void ?{}(array & a) {
+	a.size = 0;
+	a.data = 0;
+	printf("called ?{} with no a\n");
+}
+
+void ?{}(array & a, int a0) {
+	a.size = 1;
+	a.data = (int*)malloc(sizeof(int)*a.size);
+	a.data[0] = a0;
+	printf("called ?{} with a: %d\n", a0);
+}
+
+void ?{}(array & a, int a0, int a1) {
+	a.size = 2;
+	a.data = (int*)malloc(sizeof(int)*a.size);
+	a.data[0] = a0;
+	a.data[1] = a1;
+	printf("called ?{} with a: %d %d\n", a0, a1);
+}
+
+void ?{}(array & a, int a0, int a1, int a2) {
+	a.size = 3;
+	a.data = (int*)malloc(sizeof(int)*a.size);
+	a.data[0] = a0;
+	a.data[1] = a1;
+	a.data[2] = a2;
+	printf("called ?{} with a: %d %d %d\n", a0, a1, a2);
+}
+
+// test use of a tuple argument
+[void] ?{}(array & a, [int, int, int, int] args) {
+	int a0, a1, a2, a3;
+	[a0, a1, a2, a3] = args;
+	a.size = 4;
+	a.data = (int *)malloc(sizeof(int)*a.size);
+	a.data[0] = a0;
+	a.data[1] = a1;
+	a.data[2] = a2;
+	a.data[3] = a3;
+	printf("called ?{} with a: %d %d %d %d\n", a0, a1, a2, a3);
+}
+
+void print(array * x) {
+	printf("array = { ");
+	for (int i = 0; i < x->size; ++i) {
+		printf("%d, ", x->data[i]);
+	}
+	printf("}\n");
+}
+
+forall(otype T)
+T * copy(T x) {
+	// test calling new inside a polymorphic function
+	return new(x);
+}
+
+int main() {
+	array * x0 = new();
+	print(x0);
+
+	array * x1 = new(999);
+	print(x1);
+
+	array * x2 = new(123, 456);
+	print(x2);
+
+	array * x3 = new(100, 200, 300);
+	print(x3);
+
+	array * x4 = new(10, 2, 3, 4);
+	print(x4);
+
+	int * ptr = copy(111111);
+	printf("copy=%d\n", *ptr);
+
+	printf("calling func\n");
+	func(3, 2.0, 111, 4.145);
+	printf("finished func\n");
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
+
Index: src/tests/tuple/tuples.c
===================================================================
--- src/tests/tuple/tuples.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
+++ src/tests/tuple/tuples.c	(revision f3458a8c18db18bb7dfaf46579869ea14b7fb386)
@@ -0,0 +1,32 @@
+int a;
+float a;
+int f( int );
+float f( float );
+
+void g() {
+	// selects the same f each time but without a cast would be ambiguous
+	f( (int)a );
+	(int)f( a );
+}
+
+[ int ] p;
+[ int, double ] p;
+[ int, int, int ] p;
+[ int, int, int, int ] p;
+
+[ char ] q;
+[ int, int ] q;
+[ int, int, float ] q;
+[ int, int, int, int ] q;
+
+[ int, int ] r( int, int, int, int );
+
+void s() {
+	r( p, q );
+	r( [ q, p ] );
+	r( r( p, q ), r( q, q ) );
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// End: //
Index: src/tests/tupleAssign.c
===================================================================
--- src/tests/tupleAssign.c	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,66 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// tupleAssign.c --
-//
-// Author           : Rob Schluntz
-// Created On       : Tue Nov 15 17:24:32 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Mar  6 21:23:58 2017
-// Update Count     : 34
-//
-
-#include <fstream>
-
-int main() {
-	{
-		// test multiple assignment and cascading assignment
-		int u = 5, v = 6, x = 10, y = 11;
-		[int, int] z = [100, 200];
-
-		// swap x, y and store the new [x, y] in [u, v] and in z;
-		printf( "u=%d v=%d x=%d y=%d z=[%d, %d]\n", u, v, x, y, z );
-		sout | "u=" | u | "v=" | v | "x=" | x | "y=" | y | "z=[" | z | "]" | endl;
-		z = [u, v] = [x, y] = [y, x];
-		printf( "u=%d v=%d x=%d y=%d z=[%d, %d]\n", u, v, x, y, z );
-		sout | "u=" | u | "v=" | v | "x=" | x | "y=" | y | "z=[" | z | "]" | endl;
-
-		// shuffle elements -- v = z.0, z.0 = z.1, z.1 = u, u = v
-		[v, z, u] = [z, u, v];
-		printf( "u=%d v=%d z=[%d, %d]\n", u, v, z );
-		sout | "u=" | u | "v=" | v | "z=[" | z | "]" | endl;
-
-		// multiple assignment with tuple expression on right
-		z = [111, 222];
-		[u, v] = [123, 456];
-		printf( "u=%d v=%d z=[%d, %d]\n", u, v, z );
-		sout | "u=" | u | "v=" | v | "z=[" | z | "]" | endl;
-	}
-	{
-		// test mass assignment
-		double d = 0.0;
-		int i = 0;
-		char c = '\0';
-		struct X {
-			int z;
-		} x;
-		X ?=?(X & x, double d) {}
-		[int, double, int] t;
-
-		// no conversion from X to integral types, so this serves as a santiy
-		// check that as long as this compiles, ?=?(_, x) is not generated.
-		[t, x, d, i, c, x] = (double)94.12;
-		printf( "d=%lg i=%d c=%c t=[%d, %lg, %d]\n", d, i, (int)c, t );
-		sout | "d=" | d | "i=" | i | "c=" | c | ' ' | "t=[" | t | "]" | endl;
-		[x, c, i, d, x, t] = (double)-94.12;
-		printf( "d=%lg i=%d c=%c t=[%d, %lg, %d]\n", d, i, c, t );
-		sout | "d=" | d | "i=" | i | "c=" | c | ' ' | "t=[" | t | "]" | endl;
-	}
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: src/tests/tupleCast.c
===================================================================
--- src/tests/tupleCast.c	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,30 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// tupleCast.c --
-//
-// Author           : Rob Schluntz
-// Created On       : Mon Dec 12 15:56:07 2016
-// Last Modified By : Rob Schluntz
-// Last Modified On : Mon Dec 12 15:56:20 2016
-// Update Count     : 2
-//
-
-[char, int, double] f() { printf("ran f\n"); return ['c', 70, 6.28]; }
-
-int main() {
-  [int, char, float] x = [10, 'A', 3.14f];
-  printf("%d %c %g\n", ([int, char, float])x);
-  printf("%d %c\n", ([int, char])x);
-  printf("%d\n", ([int])x);
-  // printf("%d\n", (int)x);
-  printf("%g %g\n", ([double, float])x);
-  printf("%d %c\n", ([int, char])f());
-}
-
-// Local Variables: //
-// tab-width: 2 //
-// End: //
Index: src/tests/tupleFunction.c
===================================================================
--- src/tests/tupleFunction.c	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,98 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// tupleFunction.c --
-//
-// Author           : Rob Schluntz
-// Created On       : Tue Nov 15 17:24:32 2016
-// Last Modified By : Rob Schluntz
-// Last Modified On : Tue Nov 15 17:27:28 2016
-// Update Count     : 3
-//
-
-struct S {
-	int f1, f2;
-	char f3;
-	double f4;
-} v;
-
-[int] foo( [int, int, double, S] x ) {
-	printf("foo([%d, %d, %lg, {%d, %d, %c, %lg}])\n", x.0, x.1, x.2, x.3.[f1, f2, f3, f4]);
-	int a, b;
-	double c;
-	S d;
-	[a, b, c, d] = x;
-	[int, int, double, S] X = x;
-	printf("a=%d b=%d c=%lg d={%d, %d, %c, %lg}\n", a, b, c, d.[f1, f2, f3, f4]);
-	printf("X=[%d, %d, %lg, {%d, %d, %c, %lg}]\n", X.0, X.1, X.2, X.3.[f1, f2, f3, f4]);
-	return b;
-}
-
-[void] bar( [int, double, int] z ) {
-	printf("bar([%d, %lg, %d])\n", z);
-}
-
-[void] baz( int a, double b, int c ) {
-	printf("baz(%d, %lg, %d)\n", a, b, c);
-}
-
-[void] qux( [int, double] n, int m ) {
-	printf("qux([%d, %lg], %d)\n", n, m);
-}
-
-[int, double x, int] quux() {
-	return [3, 5.254, 4];
-}
-[[[int, double, int], [int, double]]] quuux() {
-	return [1, 2, 3, 4, 5];
-}
-
-int main() {
-	[int, double, int] x = [777, 2.76, 8675];
-	int x1 = 123, x3 = 456;
-	double x2 = 999.123;
-
-	printf("foo(...)=%d\n", foo(x1, x3, x2, (S){ 321, 654, 'Q', 3.14 }));
-
-	// call function with tuple parameter using tuple variable arg
-	bar(x);
-
-	// call function with tuple parameter using multiple values
-	bar(x1, x2, x3);
-
-	// call function with multiple parameters using tuple variable arg
-	baz(x);
-
-	// call function with multiple parameters using multiple args
-	baz(x1, x2, x3);
-
-	// call function with multiple parameters, one of which is a tuple using tuple variable arg
-	qux(x);
-
-	// call function with multiple parameters, one of which is a tuple using multiple args
-	qux(x1, x2, x3);
-
-	// call function with multiple return values and assign into a tuple variable
-	x = quux();
-	printf("x=[%d, %lg, %d]\n", x);
-
-	// call function with multiple return values and assign into a tuple expression
-	[x1, x2, x3] = quux();
-	printf("x1=%d x2=%lg x3=%d\n", x1, x2, x3);
-
-	// xxx - tuples of type parameters should come out as generic types?
-	// [x1, x2, x3] = ([(int)x1, (int)x2, (int)x3]) + ([(int)1, (int)2, (int)3]);
-	// ([(int)x1, (int)x2, (int)x3]) + ([(int)1, (int)2, (int)3]);
-	// printf("%d %g %d\n", x1, x2, x3);
-
-	// xxx - comes out the back as a cast, but should come out as a tuple expression of the first n fields cast to each of the result types
-	// ([int, double])x;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
-
Index: src/tests/tupleMember.c
===================================================================
--- src/tests/tupleMember.c	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,61 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// tupleFunction.c --
-//
-// Author           : Rob Schluntz
-// Created On       : Tue Nov 15 17:24:32 2016
-// Last Modified By : Rob Schluntz
-// Last Modified On : Tue Nov 15 17:27:28 2016
-// Update Count     : 3
-//
-
-void f() {
-	printf("called f!\n");
-}
-
-double g(double x, char y, int z) {
-	return z-y+x;
-}
-
-struct V2	{
-	int f2, f3;
-};
-struct V {
-	int f1;
-	V2 i; // temporary
-	// struct V2 {
-	//   int f2, f3;
-	// } i;
-	double f4;
-} v;
-
-V & h() {
-	static V local = { 111, { 222, 333 }, 444.5 };
-	return local;
-}
-
-int main() {
-	struct X {
-		int a;
-		double b;
-		char c;
-	} x = { 10, 12.5, '\x9' };
-
-	// should only call f once
-	printf("g(...)=%lg\n", g((f(), x).[b, c, a]));
-
-	v.[f1, i.[f2, f3], f4].[1.0, 2, 0, 1.1] = [11, 3.14159, 12, 13];
-
-	printf("v.[f1, i.[f2, f3], f4]=[%d, %d, %d, %lg]\n", v.[f1, i.[f2, f3], f4]);
-
-	h().[f1, i.[f2, f3], f4].[1.0, 2, 0, 1.1] = [987, 6.28, 4, 2];
-	printf("v.[f1, i.[f2, f3], f4]=[%d, [%d, %d], %lg]\n", h().[f1, i.[f2, f3], f4]);
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: src/tests/tuplePolymorphism.c
===================================================================
--- src/tests/tuplePolymorphism.c	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,74 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// tuplePolymorphism.c --
-//
-// Author           : Rob Schluntz
-// Created On       : Tue Nov 16 10:38:00 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu May 18 18:05:12 2017
-// Update Count     : 4
-//
-
-// packed is needed so that structs are not passed with the same alignment as function arguments
-__attribute__((packed)) struct A {
-	double x;
-	char y;
-	double z;
-};
-
-__attribute__((packed)) struct B {
-	long long x;
-	char y;
-	long long z;
-};
-
-// ensure that f is a viable candidate for g, even though its parameter structure does not exactly match
-[A] f([A, B] x, B y) { printf("%g %c %g %lld %c %lld %lld %c %lld\n", x.0.[x,y,z], x.1.[x,y,z], y.[x,y,z]); return x.0; }
-forall(otype T, otype U | { T f(T, U, U); })
-void g(T x, U y) { f(x, y, y); }
-
-// add two triples
-forall(otype T | { T ?+?(T, T); })
-[T, T, T] ?+?([T, T, T] x, [T, T, T] y) {
-	return [x.0+y.0, x.1+y.1, x.2+y.2];
-}
-
-int main() {
-	int x1 = 123, x3 = 456;
-	double x2 = 999.123;
-
-	int i1 = 111, i3 = 222;
-	double i2 = 333;
-
-	int d1 = 555, d3 = 444;
-	double d2 = 666;
-
-
-	[i1, i2, i3] = ([x1, (int)x2, x3]) + ([9, 2, 3]);
-	[d1, d2, d3] = ([x1, x2, x3]) + ([9, 2, 3]);
-	printf("%d %g %d\n", i1, i2, i3);
-	printf("%d %g %d\n", d1, d2, d3);
-
-	[double, double, double] zzz;
-	zzz = [x1, x2, x3];
-	printf("%g %g %g\n", zzz);
-	[x1, x2, x3] = zzz+zzz;
-	printf("%d %g %d\n", x1, x2, x3);
-
-	// ensure non-matching assertions are specialized correctly
-	g((A){ 1.21, 'x', 10.21}, (B){ 1111LL, 'v', 54385938LL });
-}
-
-forall(otype T)
-[T, T] foo([T, T] y) {
-	[T, T] x;
-	return x;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
Index: src/tests/tupleVariadic.c
===================================================================
--- src/tests/tupleVariadic.c	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,124 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// tuplePolymorphism.c --
-//
-// Author           : Rob Schluntz
-// Created On       : Fri Dec 16 10:25:35 2016
-// Last Modified By : Rob Schluntz
-// Last Modified On : Fri Dec 21 14:42:48 2016
-// Update Count     : 2
-//
-
-void func(void) {
-	printf("called func(void)\n");
-}
-forall(otype T, ttype Params | { void process(T); void func(Params); })
-void func(T arg1, Params p) {
-	process(arg1);
-	func(p);
-}
-void process(int x) {
-	printf("called process(int) %d\n", x);
-}
-void process(double x) {
-	printf("called process(double) %g\n", x);
-}
-
-forall( dtype T, ttype Params | sized(T) | { void ?{}(T &, Params); } )
-T * new(Params p);
-
-struct array {
-	int * data;
-	int size;
-};
-
-// xxx - eventually this will be collapsed...x
-void ?{}(array & a) {
-	a.size = 0;
-	a.data = 0;
-	printf("called ?{} with no a\n");
-}
-
-void ?{}(array & a, int a0) {
-	a.size = 1;
-	a.data = (int*)malloc(sizeof(int)*a.size);
-	a.data[0] = a0;
-	printf("called ?{} with a: %d\n", a0);
-}
-
-void ?{}(array & a, int a0, int a1) {
-	a.size = 2;
-	a.data = (int*)malloc(sizeof(int)*a.size);
-	a.data[0] = a0;
-	a.data[1] = a1;
-	printf("called ?{} with a: %d %d\n", a0, a1);
-}
-
-void ?{}(array & a, int a0, int a1, int a2) {
-	a.size = 3;
-	a.data = (int*)malloc(sizeof(int)*a.size);
-	a.data[0] = a0;
-	a.data[1] = a1;
-	a.data[2] = a2;
-	printf("called ?{} with a: %d %d %d\n", a0, a1, a2);
-}
-
-// test use of a tuple argument
-[void] ?{}(array & a, [int, int, int, int] args) {
-	int a0, a1, a2, a3;
-	[a0, a1, a2, a3] = args;
-	a.size = 4;
-	a.data = (int *)malloc(sizeof(int)*a.size);
-	a.data[0] = a0;
-	a.data[1] = a1;
-	a.data[2] = a2;
-	a.data[3] = a3;
-	printf("called ?{} with a: %d %d %d %d\n", a0, a1, a2, a3);
-}
-
-void print(array * x) {
-	printf("array = { ");
-	for (int i = 0; i < x->size; ++i) {
-		printf("%d, ", x->data[i]);
-	}
-	printf("}\n");
-}
-
-forall(otype T)
-T * copy(T x) {
-	// test calling new inside a polymorphic function
-	return new(x);
-}
-
-int main() {
-	array * x0 = new();
-	print(x0);
-
-	array * x1 = new(999);
-	print(x1);
-
-	array * x2 = new(123, 456);
-	print(x2);
-
-	array * x3 = new(100, 200, 300);
-	print(x3);
-
-	array * x4 = new(10, 2, 3, 4);
-	print(x4);
-
-	int * ptr = copy(111111);
-	printf("copy=%d\n", *ptr);
-
-	printf("calling func\n");
-	func(3, 2.0, 111, 4.145);
-	printf("finished func\n");
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
-
Index: src/tests/tuples.c
===================================================================
--- src/tests/tuples.c	(revision 93cdd5c0be264ba634992d1544795d31af46143b)
+++ 	(revision )
@@ -1,32 +1,0 @@
-int a;
-float a;
-int f( int );
-float f( float );
-
-void g() {
-	// selects the same f each time but without a cast would be ambiguous
-	f( (int)a );
-	(int)f( a );
-}
-
-[ int ] p;
-[ int, double ] p;
-[ int, int, int ] p;
-[ int, int, int, int ] p;
-
-[ char ] q;
-[ int, int ] q;
-[ int, int, float ] q;
-[ int, int, int, int ] q;
-
-[ int, int ] r( int, int, int, int );
-
-void s() {
-	r( p, q );
-	r( [ q, p ] );
-	r( r( p, q ), r( q, q ) );
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// End: //
