Index: src/SynTree/AddressExpr.cc
===================================================================
--- src/SynTree/AddressExpr.cc	(revision 0698aa1b5a7ea80416468a0bda92dba61d09df20)
+++ src/SynTree/AddressExpr.cc	(revision 1d776fdacfdd4e1c1e1f7ae9e1b4a6bd650bf24e)
@@ -18,12 +18,35 @@
 #include "Common/utility.h"
 
+// Address expressions are typed based on the following inference rules:
+//    E : lvalue T  &..& (n references)
+//   &E :        T *&..& (n references)
+//
+//    E : T  &..&        (m references)
+//   &E : T *&..&        (m-1 references)
+//
+// That is, lvalues becomes
+
+namespace {
+	Type * addrType( Type * type ) {
+		if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( type ) ) {
+			return new ReferenceType( refType->get_qualifiers(), addrType( refType->get_base() ) );
+		} else {
+			return new PointerType( Type::Qualifiers(), type->clone() );
+		}
+	}
+}
+
 AddressExpr::AddressExpr( Expression *arg, Expression *_aname ) : Expression( _aname ), arg( arg ) {
 	if ( arg->has_result() ) {
-		if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( arg->get_result() ) ) {
-			// xxx - very temporary, make &ref look like **
-			set_result( new PointerType( Type::Qualifiers( Type::Lvalue ), refType->get_base()->clone() ) );
+		if ( arg->get_result()->get_lvalue() ) {
+			// lvalue, retains all layers of reference and gains a pointer inside the references
+			set_result( addrType( arg->get_result() ) );
 		} else {
-			set_result( new PointerType( Type::Qualifiers(), arg->get_result()->clone() ) );
+			// taking address of non-lvalue -- must be a reference, loses one layer of reference
+			ReferenceType * refType = safe_dynamic_cast< ReferenceType * >( arg->get_result() );
+			set_result( addrType( refType->get_base() ) );
 		}
+		// result of & is never an lvalue
+		get_result()->set_lvalue( false );
 	}
 }
