Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 3d4b23fa9ef416e3543e652102009137f340d4e5)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 9a1e509e6ded571c2f6355253b2c7bfa0b4a2340)
@@ -305,4 +305,7 @@
 				std::cerr << std::endl << " to ";
 				formalType->print( std::cerr, 8 );
+				std::cerr << std::endl << "environment is: ";
+				alt.env.print( std::cerr, 8 );
+				std::cerr << std::endl;
 			)
 			Cost newCost = conversionCost( actualType, formalType, indexer, alt.env );
@@ -400,4 +403,5 @@
 			Expression * actual = actualIt->expr;
 			Type * actualType = actual->get_result();
+
 			PRINT(
 				std::cerr << "formal type is ";
@@ -643,4 +647,5 @@
 			makeExprList( instantiatedActuals, appExpr->get_args() );
 			PRINT(
+				std::cerr << "instantiate function success: " << appExpr << std::endl;
 				std::cerr << "need assertions:" << std::endl;
 				printAssertionSet( resultNeed, std::cerr, 8 );
@@ -753,5 +758,5 @@
 				PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
 				FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
-				std::cerr << "Case +++++++++++++" << std::endl;
+				std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
 				std::cerr << "formals are:" << std::endl;
 				printAll( function->get_parameters(), std::cerr, 8 );
@@ -796,5 +801,5 @@
 	bool isLvalue( Expression *expr ) {
 		// xxx - recurse into tuples?
-		return expr->has_result() && expr->get_result()->get_lvalue();
+		return expr->has_result() && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
 	}
 
@@ -882,10 +887,19 @@
 		funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
 		for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
-			if ( StructInstType *structInst = dynamic_cast< StructInstType* >( agg->expr->get_result() ) ) {
-				addAggMembers( structInst, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
-			} else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( agg->expr->get_result() ) ) {
-				addAggMembers( unionInst, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
-			} else if ( TupleType * tupleType = dynamic_cast< TupleType * >( agg->expr->get_result() ) ) {
-				addTupleMembers( tupleType, agg->expr, agg->cost, agg->env, memberExpr->get_member() );
+			// it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
+			std::unique_ptr<Expression> aggrExpr( agg->expr->clone() );
+			Type * aggrType = aggrExpr->get_result();
+			if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
+				aggrType = aggrType->stripReferences();
+				aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
+			}
+
+			// find member of the given type
+			if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
+				addAggMembers( structInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
+			} else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
+				addAggMembers( unionInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
+			} else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
+				addTupleMembers( tupleType, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
 			} // if
 		} // for
Index: src/ResolvExpr/CastCost.cc
===================================================================
--- src/ResolvExpr/CastCost.cc	(revision 3d4b23fa9ef416e3543e652102009137f340d4e5)
+++ src/ResolvExpr/CastCost.cc	(revision 9a1e509e6ded571c2f6355253b2c7bfa0b4a2340)
@@ -54,4 +54,6 @@
 		} else if ( dynamic_cast< VoidType* >( dest ) ) {
 			return Cost( 0, 0, 1 );
+		} else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
+			return convertToReferenceCost( src, refType, indexer, env );
 		} else {
 			CastCost converter( dest, indexer, env );
@@ -76,5 +78,5 @@
 			cost = Cost( 1, 0, 0 );
 		} else {
-			ConversionCost::visit( basicType );
+			cost = conversionCost( basicType, dest, indexer, env );
 		} // if
 	}
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 3d4b23fa9ef416e3543e652102009137f340d4e5)
+++ src/ResolvExpr/CommonType.cc	(revision 9a1e509e6ded571c2f6355253b2c7bfa0b4a2340)
@@ -17,5 +17,4 @@
 #include "SynTree/Type.h"
 #include "Unify.h"
-
 
 /// #define DEBUG
@@ -31,4 +30,5 @@
 		virtual void visit( PointerType *pointerType );
 		virtual void visit( ArrayType *arrayType );
+		virtual void visit( ReferenceType *refType );
 		virtual void visit( FunctionType *functionType );
 		virtual void visit( StructInstType *aggregateUseType );
@@ -42,5 +42,6 @@
 		virtual void visit( OneType *oneType );
 
-		void getCommonWithVoidPointer( PointerType* voidPointer, PointerType* otherPointer );
+		template< typename Pointer > void getCommonWithVoidPointer( Pointer* voidPointer, Pointer* otherPointer );
+		template< typename RefType > void handleRefType( RefType *inst, Type *other );
 
 		Type *result;
@@ -52,6 +53,43 @@
 	};
 
+	Type * handleReference( ReferenceType * refType, Type * other, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment & env, const OpenVarSet &openVars ) {
+		Type * result = nullptr, * common = nullptr;
+		AssertionSet have, need;
+		OpenVarSet newOpen( openVars );
+		// need unify to bind type variables
+		if ( unify( refType->get_base(), other, env, have, need, newOpen, indexer, common ) ) {
+			// std::cerr << "unify success" << std::endl;
+			if ( widenSecond ) {
+				if ( widenFirst || other->get_qualifiers() <= refType->get_qualifiers() ) {
+					result = new ReferenceType( refType->get_qualifiers(), common ); // refType->clone();
+					result->get_qualifiers() |= other->get_qualifiers();
+				}
+			} else if ( widenFirst ) {
+				if ( widenSecond || refType->get_qualifiers() <= other->get_qualifiers() ) {
+					result = common;
+					result->get_qualifiers() |= refType->get_qualifiers();
+				}
+			}
+		} else {
+			// std::cerr << "exact unify failed: " << refType << " " << other << std::endl;
+		}
+		// std::cerr << "common type of reference [" << refType << "] and non-reference [" << other << "] is [" << result << "]" << std::endl;
+		return result;
+	}
+
 	Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
 		CommonType visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
+
+		ReferenceType * refType1 = dynamic_cast< ReferenceType * >( type1 );
+		ReferenceType * refType2 = dynamic_cast< ReferenceType * >( type2 );
+		if ( (refType1 || refType2) && (! refType1 || ! refType2) ) {
+			// handle the case where exactly one of the types is a reference type specially
+			if ( refType1 ) {
+				return handleReference( refType1, type2, widenFirst, widenSecond, indexer, env, openVars );
+			} else if ( refType2 ) {
+				return handleReference( refType2, type1, widenSecond, widenFirst, indexer, env, openVars );
+			}
+		}
+
 		type1->accept( visitor );
 		Type *result = visitor.get_result();
@@ -142,5 +180,6 @@
 	}
 
-	void CommonType::getCommonWithVoidPointer( PointerType* voidPointer, PointerType* otherPointer ) {
+	template< typename Pointer >
+	void CommonType::getCommonWithVoidPointer( Pointer* voidPointer, Pointer* otherPointer ) {
 		if ( TypeInstType* var = dynamic_cast< TypeInstType* >( otherPointer->get_base() ) ) {
 			OpenVarSet::const_iterator entry = openVars.find( var->get_name() );
@@ -188,4 +227,37 @@
 
 	void CommonType::visit( __attribute((unused)) ArrayType *arrayType ) {}
+
+	void CommonType::visit( ReferenceType *refType ) {
+		if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
+			if ( widenFirst && dynamic_cast< VoidType* >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {
+				getCommonWithVoidPointer( otherRef, refType );
+			} else if ( widenSecond && dynamic_cast< VoidType* >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {
+				getCommonWithVoidPointer( refType, otherRef );
+			} else if ( ( refType->get_base()->get_qualifiers() >= otherRef->get_base()->get_qualifiers() || widenFirst )
+					   && ( refType->get_base()->get_qualifiers() <= otherRef->get_base()->get_qualifiers() || widenSecond ) ) {
+				Type::Qualifiers tq1 = refType->get_base()->get_qualifiers(), tq2 = otherRef->get_base()->get_qualifiers();
+				refType->get_base()->get_qualifiers() = Type::Qualifiers();
+				otherRef->get_base()->get_qualifiers() = Type::Qualifiers();
+				AssertionSet have, need;
+				OpenVarSet newOpen( openVars );
+				if ( unifyExact( refType->get_base(), otherRef->get_base(), env, have, need, newOpen, indexer ) ) {
+					if ( tq1 < tq2 ) {
+						result = refType->clone();
+					} else {
+						result = otherRef->clone();
+					} // if
+					result->get_qualifiers() = tq1 | tq2;
+				} else {
+					/// std::cout << "place for ptr-to-type" << std::endl;
+				} // if
+				refType->get_base()->get_qualifiers() = tq1;
+				otherRef->get_base()->get_qualifiers() = tq2;
+			} // if
+		} else if ( widenSecond && dynamic_cast< ZeroType* >( type2 ) ) {
+			result = refType->clone();
+			result->get_qualifiers() |= type2->get_qualifiers();
+		} // if
+	}
+
 	void CommonType::visit( __attribute((unused)) FunctionType *functionType ) {}
 	void CommonType::visit( __attribute((unused)) StructInstType *aggregateUseType ) {}
@@ -195,8 +267,7 @@
 		if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) {
 			// reuse BasicType, EnumInstType code by swapping type2 with enumInstType
-			Type * temp = type2;
+			ValueGuard< Type * > temp( type2 );
 			type2 = enumInstType;
-			temp->accept( *this );
-			type2 = temp;
+			temp.old->accept( *this );
 		} // if
 	}
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 3d4b23fa9ef416e3543e652102009137f340d4e5)
+++ src/ResolvExpr/ConversionCost.cc	(revision 9a1e509e6ded571c2f6355253b2c7bfa0b4a2340)
@@ -57,4 +57,7 @@
 		} else if ( dynamic_cast< VoidType* >( dest ) ) {
 			return Cost( 0, 0, 1 );
+		} else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
+			// std::cerr << "conversionCost: dest is reference" << std::endl;
+			return convertToReferenceCost( src, refType, indexer, env );
 		} else {
 			ConversionCost converter( dest, indexer, env );
@@ -66,4 +69,45 @@
 			} // if
 		} // if
+	}
+
+	Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
+		// std::cerr << "convert to reference cost..." << std::endl;
+		if ( ReferenceType *srcAsRef = dynamic_cast< ReferenceType * >( src ) ) { // pointer-like conversions between references
+			// std::cerr << "converting between references" << std::endl;
+			if ( srcAsRef->get_base()->get_qualifiers() <= dest->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( srcAsRef->get_base(), dest->get_base(), indexer, env ) ) {
+				return Cost( 0, 0, 1 );
+			} else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
+				int assignResult = ptrsAssignable( srcAsRef->get_base(), dest->get_base(), env );
+				if ( assignResult < 0 ) {
+					return Cost( 0, 0, 1 );
+				} else if ( assignResult > 0 ) {
+					return Cost( 1, 0, 0 );
+				} // if
+			} // if
+		} else if ( typesCompatibleIgnoreQualifiers( src, dest->get_base(), indexer, env ) ) {
+			// std::cerr << "converting compatible base type" << std::endl;
+			if ( src->get_lvalue() ) {
+				// std::cerr << "lvalue to reference conversion" << std::endl;
+				// lvalue-to-reference conversion:  cv lvalue T => cv T &
+				if ( src->get_qualifiers() == dest->get_base()->get_qualifiers() ) {
+					return Cost( 0, 0, 1 ); // cost needs to be non-zero to add cast
+				} if ( src->get_qualifiers() < dest->get_base()->get_qualifiers() ) {
+					return Cost( 0, 0, 2 ); // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
+				} else {
+					return Cost( 1, 0, 0 );
+				}
+			} else if ( dest->get_base()->get_const() ) {
+				// std::cerr << "rvalue to const ref conversion" << std::endl;
+				// rvalue-to-const-reference conversion: T => const T &
+				return Cost( 0, 0, 1 );
+			} else {
+				// std::cerr << "rvalue to non-const reference conversion" << std::endl;
+				// rvalue-to-reference conversion: T => T &
+				return Cost( 1, 0, 0 );
+			}
+		} else {
+			// std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl;
+		}
+		return Cost::infinity;
 	}
 
@@ -173,5 +217,5 @@
 			if ( pointerType->get_base()->get_qualifiers() <= destAsPtr->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
 				cost = Cost( 0, 0, 1 );
-			} else {
+			} else {  // xxx - this discards pointer qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
 				int assignResult = ptrsAssignable( pointerType->get_base(), destAsPtr->get_base(), env );
 				if ( assignResult < 0 ) {
@@ -187,4 +231,14 @@
 
 	void ConversionCost::visit(__attribute((unused)) ArrayType *arrayType) {}
+
+	void ConversionCost::visit(ReferenceType *refType) {
+		// Note: dest can never be a reference, since it would have been caught in an earlier check
+		assert( ! dynamic_cast< ReferenceType * >( dest ) );
+		// convert reference to rvalue: cv T1 & => T2
+		// recursively compute conversion cost from T1 to T2.
+		// cv can be safely dropped because of 'implicit dereference' behavior.
+		refType->get_base()->accept( *this );
+	}
+
 	void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {}
 
@@ -208,5 +262,5 @@
 		static Type::Qualifiers q;
 		static BasicType integer( q, BasicType::SignedInt );
-		integer.accept( *this );
+		integer.accept( *this );  // safe if dest >= int
 		if ( cost < Cost( 1, 0, 0 ) ) {
 			cost.incSafe();
Index: src/ResolvExpr/ConversionCost.h
===================================================================
--- src/ResolvExpr/ConversionCost.h	(revision 3d4b23fa9ef416e3543e652102009137f340d4e5)
+++ src/ResolvExpr/ConversionCost.h	(revision 9a1e509e6ded571c2f6355253b2c7bfa0b4a2340)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// ConversionCost.h -- 
+// ConversionCost.h --
 //
 // Author           : Richard C. Bilson
@@ -26,5 +26,5 @@
 	  public:
 		ConversionCost( Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env );
-  
+
 		Cost get_cost() const { return cost; }
 
@@ -33,4 +33,5 @@
 		virtual void visit(PointerType *pointerType);
 		virtual void visit(ArrayType *arrayType);
+		virtual void visit(ReferenceType *refType);
 		virtual void visit(FunctionType *functionType);
 		virtual void visit(StructInstType *aggregateUseType);
@@ -49,4 +50,6 @@
 		const TypeEnvironment &env;
 	};
+
+	Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env );
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 3d4b23fa9ef416e3543e652102009137f340d4e5)
+++ src/ResolvExpr/Unify.cc	(revision 9a1e509e6ded571c2f6355253b2c7bfa0b4a2340)
@@ -42,4 +42,5 @@
 		virtual void visit(PointerType *pointerType);
 		virtual void visit(ArrayType *arrayType);
+		virtual void visit(ReferenceType *refType);
 		virtual void visit(FunctionType *functionType);
 		virtual void visit(StructInstType *aggregateUseType);
@@ -428,4 +429,12 @@
 	}
 
+	void Unify::visit(ReferenceType *refType) {
+		if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
+			result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
+			markAssertions( haveAssertions, needAssertions, refType );
+			markAssertions( haveAssertions, needAssertions, otherRef );
+		} // if
+	}
+
 	void Unify::visit(ArrayType *arrayType) {
 		ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
