Index: src/Common/Debug.h
===================================================================
--- src/Common/Debug.h	(revision af1ed1ad2b8ed8a9b4d0d4da3f9dc306176a97fc)
+++ src/Common/Debug.h	(revision b5563e1f1d228b7c95815b2fddbff04bbb84de4b)
@@ -28,5 +28,5 @@
 namespace Debug {
 	/// debug codegen a translation unit
-	static inline void codeGen( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label, LinkageSpec::Spec linkageFilter = LinkageSpec::Compiler ) {
+	static inline void codeGen( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label, __attribute__((unused)) LinkageSpec::Spec linkageFilter = LinkageSpec::Compiler ) {
 	#ifdef DEBUG
 		std::list< Declaration * > decls;
@@ -41,5 +41,5 @@
 	} // dump
 
-	static inline void treeDump( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label, LinkageSpec::Spec linkageFilter = LinkageSpec::Compiler ) {
+	static inline void treeDump( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label, __attribute__((unused)) LinkageSpec::Spec linkageFilter = LinkageSpec::Compiler ) {
 	#ifdef DEBUG
 		std::list< Declaration * > decls;
Index: src/GenPoly/Lvalue.cc
===================================================================
--- src/GenPoly/Lvalue.cc	(revision af1ed1ad2b8ed8a9b4d0d4da3f9dc306176a97fc)
+++ src/GenPoly/Lvalue.cc	(revision b5563e1f1d228b7c95815b2fddbff04bbb84de4b)
@@ -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 ) );
 						}
 					}
Index: src/tests/.expect/references.txt
===================================================================
--- src/tests/.expect/references.txt	(revision af1ed1ad2b8ed8a9b4d0d4da3f9dc306176a97fc)
+++ src/tests/.expect/references.txt	(revision b5563e1f1d228b7c95815b2fddbff04bbb84de4b)
@@ -4,4 +4,8 @@
 13 1 12
 14 14
+x = 6 ; x2 = 789
+x = 6 ; x2 = 999
+x = 12345 ; x2 = 999
+x = 22222 ; x2 = 999
 Default constructing a Y
 Copy constructing a Y
Index: src/tests/references.c
===================================================================
--- src/tests/references.c	(revision af1ed1ad2b8ed8a9b4d0d4da3f9dc306176a97fc)
+++ src/tests/references.c	(revision b5563e1f1d228b7c95815b2fddbff04bbb84de4b)
@@ -46,13 +46,9 @@
 
 int main() {
-	int x = 123456, *p1 = &x, **p2 = &p1, ***p3 = &p2,
+	int x = 123456, x2 = 789, *p1 = &x, **p2 = &p1, ***p3 = &p2,
 		&r1 = x,    &&r2 = r1,   &&&r3 = r2;
 	***p3 = 3;                          // change x
-	// ((int&)r3 = 3;                      // change x, ***r3
 	**p3 = &x;                          // change p1
-	// ((int*&)&r3) = &x;                  // change r1, (&*)**r3
 	*p3 = &p1;                          // change p2
-	// ((int**&)&&r3) = &p2;               // change r2, (&(&*)*)*r3
-	// ((int***&)&&&r3) = p3;              // change r3 to p3, (&(&(&*)*)*)r3
 	int y = 0, z = 11, & ar[3] = { x, y, z };    // initialize array of references
 	// &ar[1] = &z;                        // change reference array element
@@ -62,4 +58,6 @@
 	// sizeof( &ar[1] ) == sizeof( int *); // is true, i.e., the size of a reference
 
+	((int*&)&r3) = &x;                  // change r1, (&*)**r3
+	x = 3;
 	// test that basic reference properties are true - r1 should be an alias for x
 	printf("%d %d %d\n", x, r1, &x == &r1);
@@ -76,4 +74,16 @@
 	changeRef( r1 );
 	printf("%d %d\n", r1, x);
+
+	((int&)r3) = 6;                       // change x, ***r3
+	printf("x = %d ; x2 = %d\n", x, x2);  // check that x was changed
+	((int*&)&r3) = &x2;                   // change r1 to refer to x2, (&*)**r3
+	((int&)r3) = 999;                     // modify x2
+	printf("x = %d ; x2 = %d\n", x, x2);  // check that x2 was changed
+	((int**&)&&r3) = p2;                  // change r2, (&(&*)*)*r3
+	((int&)r3) = 12345;                   // modify x
+	printf("x = %d ; x2 = %d\n", x, x2);  // check that x was changed
+	((int***&)&&&r3) = p3;                // change r3 to p3, (&(&(&*)*)*)r3
+	((int&)r3) = 22222;                   // modify x
+	printf("x = %d ; x2 = %d\n", x, x2);  // check that x was changed
 
 	// test that reference members are not implicitly constructed/destructed/assigned
