Index: src/GenPoly/Lvalue.cc
===================================================================
--- src/GenPoly/Lvalue.cc	(revision a4d188fa9bbc44789d6a360cac9dc109d8e4774c)
+++ src/GenPoly/Lvalue.cc	(revision 6040e67da4f1afa6550d4e3339f24a66a4be8fc3)
@@ -45,4 +45,5 @@
 		Expression * mkDeref( Expression * arg ) {
 			if ( SymTab::dereferenceOperator ) {
+				// note: reference depth can be arbitrarily deep here, so peel off the outermost pointer/reference, not just pointer because they are effecitvely equivalent in this pass
 				VariableExpr * deref = new VariableExpr( SymTab::dereferenceOperator );
 				deref->result = new PointerType( Type::Qualifiers(), deref->result );
@@ -197,18 +198,23 @@
 					PRINT(
 						std::cerr << "pair<0>: " << arg << std::endl;
+						std::cerr << " -- " << arg->result << std::endl;
 						std::cerr << "pair<1>: " << formal << std::endl;
 					)
 					if ( dynamic_cast<ReferenceType*>( formal ) ) {
-						if ( isIntrinsicReference( arg ) ) { // do not combine conditions, because that changes the meaning of the else if
-							if ( function->get_linkage() != LinkageSpec::Intrinsic ) { // intrinsic functions that turn pointers into references
-								// if argument is dereference or array subscript, the result isn't REALLY a reference, so it's not necessary to fix the argument
-								PRINT(
-									std::cerr << "===is intrinsic arg in non-intrinsic call - adding address" << std::endl;
-								)
-								arg = new AddressExpr( arg );
-							}
-						} else if ( function->get_linkage() == LinkageSpec::Intrinsic ) {
-							// std::cerr << "===adding deref to arg" << std::endl;
-							// if the parameter is a reference, add a dereference to the reference-typed argument.
+						PRINT(
+							std::cerr << "===formal is reference" << std::endl;
+						)
+						// TODO: it's likely that the second condition should be ... && ! isIntrinsicReference( arg ), but this requires investigation.
+						if ( function->get_linkage() != LinkageSpec::Intrinsic && isIntrinsicReference( arg ) ) {
+							// if argument is dereference or array subscript, the result isn't REALLY a reference, but non-intrinsic functions expect a reference: take address
+							PRINT(
+								std::cerr << "===is intrinsic arg in non-intrinsic call - adding address" << std::endl;
+							)
+							arg = new AddressExpr( arg );
+						} else if ( function->get_linkage() == LinkageSpec::Intrinsic && arg->result->referenceDepth() != 0 ) {
+							// argument is a 'real' reference, but function expects a C lvalue: add a dereference to the reference-typed argument
+							PRINT(
+								std::cerr << "===is non-intrinsic arg in intrinsic call - adding deref to arg" << std::endl;
+							)
 							Type * baseType = InitTweak::getPointerBase( arg->result );
 							assertf( baseType, "parameter is reference, arg must be pointer or reference: %s", toString( arg->result ).c_str() );
@@ -217,4 +223,5 @@
 							arg->set_result( ptrType );
 							arg = mkDeref( arg );
+							assertf( arg->result->referenceDepth() == 0, "Reference types should have been eliminated from intrinsic function calls, but weren't: %s", toCString( arg->result ) );
 						}
 					}
