Index: src/GenPoly/Lvalue.cc
===================================================================
--- src/GenPoly/Lvalue.cc	(revision 9a34b5af88e34afea5a43c4d02c330da9e0defc6)
+++ src/GenPoly/Lvalue.cc	(revision cb434518055bb986f86735395964571c3f085a38)
@@ -39,4 +39,10 @@
 // need to be careful about polymorphic references... e.g. in *? (___operator_deref__A0_1_0_0__Fd0_Pd0_intrinsic___1)
 // the variable is automatically dereferenced and this causes errors dereferencing void*.
+
+#if 0
+#define PRINT(x) x
+#else
+#define PRINT(x)
+#endif
 
 namespace GenPoly {
@@ -79,4 +85,10 @@
 			Expression * postmutate( AddressExpr * addressExpr );
 		};
+
+		/// Removes redundant &*/*& pattern that this pass can generate
+		struct CollapseAddrDeref final {
+			Expression * postmutate( AddressExpr * addressExpr );
+			Expression * postmutate( ApplicationExpr * appExpr );
+		};
 	} // namespace
 
@@ -87,8 +99,10 @@
 		PassVisitor<GeneralizedLvalue> genLval;
 		PassVisitor<FixIntrinsicArgs> fixer;
+		PassVisitor<CollapseAddrDeref> collapser;
 		mutateAll( translationUnit, refCvt );
 		mutateAll( translationUnit, fixer );
 		mutateAll( translationUnit, elim );
 		mutateAll( translationUnit, genLval );
+		mutateAll( translationUnit, collapser );
 	}
 
@@ -139,8 +153,9 @@
 				delete arg->get_result();
 				arg->set_result( ptrType );
-				arg = mkDeref( new CastExpr( arg, arg->get_result()->clone() ) );
-			}
-		}
-
+				arg = mkDeref( arg );
+			}
+		}
+
+		// xxx - might need to & every * (or every * that is an arg to non-intrinsic function??)
 		Expression * FixIntrinsicArgs::postmutate( ApplicationExpr * appExpr ) {
 			// intrinsic functions don't really take reference-typed parameters, so they require an implicit dereference on their arguments.
@@ -152,9 +167,11 @@
 						Expression *& arg = std::get<0>( p );
 						DeclarationWithType * formal = std::get<1>( p );
-						std::cerr << "pair<0>: " << arg << std::endl;
-						std::cerr << "pair<1>: " << formal->get_type() << std::endl;
+						PRINT(
+							std::cerr << "pair<0>: " << arg << std::endl;
+							std::cerr << "pair<1>: " << formal->get_type() << std::endl;
+						)
 						if ( isIntrinsicReference( arg ) ) { // 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
-							std::cerr << "skipping intrinsic reference" << std::endl;
+							PRINT( std::cerr << "skipping intrinsic reference" << std::endl; )
 							continue;
 						} else {
@@ -181,9 +198,11 @@
 					// nothing to do if casting from reference to reference.
 					(void)otherRef;
-					std::cerr << "convert reference to reference -- nop" << std::endl;
+					PRINT( std::cerr << "convert reference to reference -- nop" << std::endl; )
 					if ( isIntrinsicReference( castExpr->get_arg() ) ) {
 						Expression * callExpr = castExpr->get_arg();
-						std::cerr << "but arg is deref -- &" << std::endl;
-						std::cerr << callExpr << std::endl;
+						PRINT(
+							std::cerr << "but arg is deref -- &" << std::endl;
+							std::cerr << callExpr << std::endl;
+						)
 						// move environment out to new top-level
 						callExpr->set_env( castExpr->get_env() );
@@ -194,5 +213,5 @@
 					}
 					assertf( false, "non-intrinsic reference with cast of reference to reference not yet supported: ", toString( castExpr ) );
-					std::cerr << castExpr << std::endl;
+					PRINT( std::cerr << castExpr << std::endl; )
 					return castExpr;
 				} else if ( castExpr->get_arg()->get_result()->get_lvalue() ) {
@@ -200,7 +219,15 @@
 					// xxx - keep cast, but turn into pointer cast??
 					// xxx - memory
-					std::cerr << "convert lvalue to reference -- &" << std::endl;
-					std::cerr << castExpr->get_arg() << std::endl;
-					Expression * ret = new AddressExpr( castExpr->get_arg() );
+					PRINT(
+						std::cerr << "convert lvalue to reference -- &" << std::endl;
+						std::cerr << castExpr->get_arg() << std::endl;
+					)
+					AddressExpr * ret = new AddressExpr( castExpr->get_arg() );
+					if ( refType->get_base()->get_qualifiers() != castExpr->get_arg()->get_result()->get_qualifiers() ) {
+						// must keep cast if cast-to type is different from the actual type
+						castExpr->set_arg( ret );
+
+						return castExpr;
+					}
 					ret->set_env( castExpr->get_env() );
 					castExpr->set_env( nullptr );
@@ -215,10 +242,10 @@
 				// conversion from reference to rvalue
 				// should be easy, just need to move deref code up here?
-				std::cerr << "convert reference to rvalue -- *" << std::endl;
+				PRINT( std::cerr << "convert reference to rvalue -- *" << std::endl; )
 				if ( isIntrinsicReference( castExpr->get_arg() ) ) {
-					std::cerr << "but arg is intrinsic reference -- nop" << std::endl;
+					PRINT( std::cerr << "but arg is intrinsic reference -- nop" << std::endl; )
 					return castExpr;
 				}
-				std::cerr << "was = " << castExpr << std::endl;
+				PRINT( std::cerr << "was = " << castExpr << std::endl; )
 
 				Expression * deref = mkDeref( castExpr->get_arg() );
@@ -227,5 +254,5 @@
 				castExpr->set_env( nullptr );
 				delete castExpr;
-				std::cerr << "now: " << deref << std::endl;
+				PRINT( std::cerr << "now: " << deref << std::endl; )
 				return deref;
 			}
@@ -255,4 +282,43 @@
 			return addrExpr;
 		}
+
+		Expression * CollapseAddrDeref::postmutate( AddressExpr * addressExpr ) {
+			Expression * arg = addressExpr->get_arg();
+			if ( isIntrinsicReference( arg ) ) {
+				std::string fname = InitTweak::getFunctionName( arg );
+				if ( fname == "*?" ) {
+					Expression *& arg0 = InitTweak::getCallArg( arg, 0 );
+					Expression * ret = arg0;
+					ret->set_env( addressExpr->get_env() );
+					arg0 = nullptr;
+					addressExpr->set_env( nullptr );
+					delete addressExpr;
+					return ret;
+				}
+			}
+			return addressExpr;
+		}
+
+		Expression * CollapseAddrDeref::postmutate( ApplicationExpr * appExpr ) {
+			if ( isIntrinsicReference( appExpr ) ) {
+				std::string fname = InitTweak::getFunctionName( appExpr );
+				if ( fname == "*?" ) {
+					Expression * arg = InitTweak::getCallArg( appExpr, 0 );
+					// xxx - this isn't right, because it can remove casts that should be there...
+					// while ( CastExpr * castExpr = dynamic_cast< CastExpr * >( arg ) ) {
+					// 	arg = castExpr->get_arg();
+					// }
+					if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( arg ) ) {
+						Expression * ret = addrExpr->get_arg();
+						ret->set_env( appExpr->get_env() );
+						addrExpr->set_arg( nullptr );
+						appExpr->set_env( nullptr );
+						delete appExpr;
+						return ret;
+					}
+				}
+			}
+			return appExpr;
+		}
 	} // namespace
 } // namespace GenPoly
