Index: src/Common/Debug.h
===================================================================
--- src/Common/Debug.h	(revision c5ce0ecd56e67e949d0b059b405df1120ed18b85)
+++ src/Common/Debug.h	(revision d2034b4821bf389f33b55c7285d2540e23596684)
@@ -28,23 +28,23 @@
 namespace Debug {
 	/// debug codegen a translation unit
-	static inline void codeGen( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label ) {
+	static inline void codeGen( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label, LinkageSpec::Spec linkageFilter = LinkageSpec::Compiler ) {
 	#ifdef DEBUG
 		std::list< Declaration * > decls;
 
-		filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), []( Declaration * decl ) {
-			return ! LinkageSpec::isBuiltin( decl->get_linkage() );
+		filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), [linkageFilter]( Declaration * decl ) {
+			return ! (decl->linkage & linkageFilter);
 		});
 
 		std::cerr << "======" << label << "======" << std::endl;
-		CodeGen::generate( decls, std::cerr, false, true );
+		CodeGen::generate( decls, std::cerr, true, true );
 	#endif
 	} // dump
 
-	static inline void treeDump( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label ) {
+	static inline void treeDump( __attribute__((unused)) const std::list< Declaration * > & translationUnit, __attribute__((unused)) const std::string & label, LinkageSpec::Spec linkageFilter = LinkageSpec::Compiler ) {
 	#ifdef DEBUG
 		std::list< Declaration * > decls;
 
-		filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), []( Declaration * decl ) {
-			return ! LinkageSpec::isBuiltin( decl->get_linkage() );
+		filter( translationUnit.begin(), translationUnit.end(), back_inserter( decls ), [linkageFilter]( Declaration * decl ) {
+			return ! (decl->linkage & linkageFilter);
 		});
 
Index: src/Common/SemanticError.h
===================================================================
--- src/Common/SemanticError.h	(revision c5ce0ecd56e67e949d0b059b405df1120ed18b85)
+++ src/Common/SemanticError.h	(revision d2034b4821bf389f33b55c7285d2540e23596684)
@@ -38,8 +38,10 @@
 constexpr const char * const WarningFormats[] = {
 	"self assignment of expression: %s",
+	"rvalue to reference conversion of rvalue: %s",
 };
 
 enum class Warning {
 	SelfAssignment,
+	RvalueToReferenceConversion,
 	NUMBER_OF_WARNINGS, //This MUST be the last warning
 };
@@ -50,5 +52,6 @@
 );
 
-#define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id], __VA_ARGS__)
+// ## used here to allow empty __VA_ARGS__
+#define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id], ## __VA_ARGS__)
 
 void SemanticWarningImpl (CodeLocation loc, Warning warn, const char * const fmt, ...) __attribute__((format(printf, 3, 4)));
Index: src/GenPoly/Lvalue.cc
===================================================================
--- src/GenPoly/Lvalue.cc	(revision c5ce0ecd56e67e949d0b059b405df1120ed18b85)
+++ src/GenPoly/Lvalue.cc	(revision d2034b4821bf389f33b55c7285d2540e23596684)
@@ -59,5 +59,5 @@
 		}
 
-		struct ReferenceConversions final {
+		struct ReferenceConversions final : public WithStmtsToAdd {
 			Expression * postmutate( CastExpr * castExpr );
 			Expression * postmutate( AddressExpr * addrExpr );
@@ -114,5 +114,5 @@
 	}
 
-	void convertLvalue( std::list< Declaration* >& translationUnit ) {
+	void convertLvalue( std::list< Declaration* > & translationUnit ) {
 		PassVisitor<ReferenceConversions> refCvt;
 		PassVisitor<ReferenceTypeElimination> elim;
@@ -150,6 +150,6 @@
 					// use type of return variable rather than expr result type, since it may have been changed to a pointer type
 					FunctionType * ftype = GenPoly::getFunctionType( func->get_type() );
-					Type * ret = ftype->get_returnVals().empty() ? nullptr : ftype->get_returnVals().front()->get_type();
-					return func->get_linkage() == LinkageSpec::Intrinsic && dynamic_cast<ReferenceType *>( ret );
+					Type * ret = ftype->returnVals.empty() ? nullptr : ftype->returnVals.front()->get_type();
+					return func->linkage == LinkageSpec::Intrinsic && dynamic_cast<ReferenceType *>( ret );
 				}
 			}
@@ -160,13 +160,12 @@
 			if ( isIntrinsicReference( appExpr ) ) {
 				// eliminate reference types from intrinsic applications - now they return lvalues
-				Type * result = appExpr->get_result();
-				appExpr->set_result( result->stripReferences()->clone() );
-				appExpr->get_result()->set_lvalue( true );
+				Type * result = appExpr->result;
+				appExpr->result = result->stripReferences()->clone();
+				appExpr->result->set_lvalue( true );
 				if ( ! inIntrinsic ) {
 					// when not in an intrinsic function, add a cast to
 					// don't add cast when in an intrinsic function, since they already have the cast
 					Expression * ret = new CastExpr( appExpr, result );
-					ret->set_env( appExpr->get_env() );
-					appExpr->set_env( nullptr );
+					std::swap( ret->env, appExpr->env );
 					return ret;
 				}
@@ -187,10 +186,10 @@
 				assertf( ftype, "Function declaration does not have function type." );
 				// can be of differing lengths only when function is variadic
-				assertf( ftype->get_parameters().size() == appExpr->get_args().size() || ftype->get_isVarArgs(), "ApplicationExpr args do not match formal parameter type." );
+				assertf( ftype->parameters.size() == appExpr->args.size() || ftype->isVarArgs, "ApplicationExpr args do not match formal parameter type." );
 
 
 				unsigned int i = 0;
-				const unsigned int end = ftype->get_parameters().size();
-				for ( auto p : unsafe_group_iterate( appExpr->get_args(), ftype->get_parameters() ) ) {
+				const unsigned int end = ftype->parameters.size();
+				for ( auto p : unsafe_group_iterate( appExpr->args, ftype->parameters ) ) {
 					if (i == end) break;
 					Expression *& arg = std::get<0>( p );
@@ -212,8 +211,8 @@
 							// std::cerr << "===adding deref to arg" << std::endl;
 							// if the parameter is a reference, add a dereference to the reference-typed argument.
-							Type * baseType = InitTweak::getPointerBase( arg->get_result() );
-							assertf( baseType, "parameter is reference, arg must be pointer or reference: %s", toString( arg->get_result() ).c_str() );
+							Type * baseType = InitTweak::getPointerBase( arg->result );
+							assertf( baseType, "parameter is reference, arg must be pointer or reference: %s", toString( arg->result ).c_str() );
 							PointerType * ptrType = new PointerType( Type::Qualifiers(), baseType->clone() );
-							delete arg->get_result();
+							delete arg->result;
 							arg->set_result( ptrType );
 							arg = mkDeref( arg );
@@ -249,7 +248,7 @@
 		Expression * AddrRef::postmutate( AddressExpr * addrExpr ) {
 			if ( refDepth == 0 ) {
-				if ( ! isIntrinsicReference( addrExpr->get_arg() ) ) {
+				if ( ! isIntrinsicReference( addrExpr->arg ) ) {
 					// try to avoid ?[?]
-					refDepth = addrExpr->get_arg()->get_result()->referenceDepth();
+					refDepth = addrExpr->arg->result->referenceDepth();
 				}
 			}
@@ -280,131 +279,102 @@
 			// pointer casts in the right places.
 
-			// conversion to reference type
-			if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( castExpr->get_result() ) ) {
-				(void)refType;
-				if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( castExpr->get_arg()->get_result() ) ) {
-					// nothing to do if casting from reference to reference.
-					(void)otherRef;
-					PRINT( std::cerr << "convert reference to reference -- nop" << std::endl; )
-					if ( isIntrinsicReference( castExpr->get_arg() ) ) {
-						Expression * callExpr = castExpr->get_arg();
-						PRINT(
-							std::cerr << "but arg is deref -- &" << std::endl;
-							std::cerr << callExpr << std::endl;
-						)
-						callExpr = new AddressExpr( callExpr ); // this doesn't work properly for multiple casts
-						delete callExpr->get_result();
-						callExpr->set_result( refType->clone() );
-						// move environment out to new top-level
-						callExpr->set_env( castExpr->get_env() );
-						castExpr->set_arg( nullptr );
-						castExpr->set_env( nullptr );
-						delete castExpr;
-						return callExpr;
-					}
-					int depth1 = refType->referenceDepth();
-					int depth2 = otherRef->referenceDepth();
-					int diff = depth1-depth2;
-					if ( diff == 0 ) {
-						// conversion between references of the same depth
-						assertf( depth1 == depth2, "non-intrinsic reference with cast of reference to reference not yet supported: %d %d %s", depth1, depth2, toString( castExpr ).c_str() );
-						PRINT( std::cerr << castExpr << std::endl; )
-						return castExpr;
-					} else if ( diff < 0 ) {
-						// conversion from reference to reference with less depth (e.g. int && -> int &): add dereferences
-						Expression * ret = castExpr->arg;
-						for ( int i = 0; i < diff; ++i ) {
-							ret = mkDeref( ret );
-						}
-						ret->env = castExpr->env;
-						delete ret->result;
-						ret->result = castExpr->result;
-						ret->result->set_lvalue( true ); // ensure result is lvalue
-						castExpr->env = nullptr;
-						castExpr->arg = nullptr;
-						castExpr->result = nullptr;
-						delete castExpr;
-						return ret;
-					} else if ( diff > 0 ) {
-						// conversion from reference to reference with more depth (e.g. int & -> int &&): add address-of
-						Expression * ret = castExpr->arg;
-						for ( int i = 0; i < diff; ++i ) {
-							ret = new AddressExpr( ret );
-						}
-						ret->env = castExpr->env;
-						delete ret->result;
-						ret->result = castExpr->result;
-						castExpr->env = nullptr;
-						castExpr->arg = nullptr;
-						castExpr->result = nullptr;
-						delete castExpr;
-						return ret;
-					}
-
-					assertf( depth1 == depth2, "non-intrinsic reference with cast of reference to reference not yet supported: %d %d %s", depth1, depth2, toString( castExpr ).c_str() );
-					PRINT( std::cerr << castExpr << std::endl; )
+			// Note: reference depth difference is the determining factor in what code is run, rather than whether something is
+			// reference type or not, since conversion still needs to occur when both types are references that differ in depth.
+
+			Type * destType = castExpr->result;
+			Type * srcType = castExpr->arg->result;
+			int depth1 = destType->referenceDepth();
+			int depth2 = srcType->referenceDepth();
+			int diff = depth1 - depth2;
+
+			if ( diff > 0 && ! srcType->get_lvalue() ) {
+				// rvalue to reference conversion -- introduce temporary
+				// know that reference depth of cast argument is 0, need to introduce n temporaries for reference depth of n, e.g.
+				//   (int &&&)3;
+				// becomes
+				//   int __ref_tmp_0 = 3;
+				//   int & __ref_tmp_1 = _&_ref_tmp_0;
+				//   int && __ref_tmp_2 = &__ref_tmp_1;
+				//   &__ref_tmp_2;
+				// the last & comes from the remaining reference conversion code
+				SemanticWarning( castExpr->arg->location, Warning::RvalueToReferenceConversion, toCString( castExpr->arg ) );
+
+				static UniqueName tempNamer( "__ref_tmp_" );
+				ObjectDecl * temp = ObjectDecl::newObject( tempNamer.newName(), castExpr->arg->result->clone(), new SingleInit( castExpr->arg ) );
+				PRINT( std::cerr << "made temp: " << temp << std::endl; )
+				stmtsToAddBefore.push_back( new DeclStmt( temp ) );
+				for ( int i = 0; i < depth1-1; i++ ) { // xxx - maybe this should be diff-1? check how this works with reference type for srcType
+					ObjectDecl * newTemp = ObjectDecl::newObject( tempNamer.newName(), new ReferenceType( Type::Qualifiers(), temp->type->clone() ), new SingleInit( new AddressExpr( new VariableExpr( temp ) ) ) );
+					PRINT( std::cerr << "made temp" << i << ": " << newTemp << std::endl; )
+					stmtsToAddBefore.push_back( new DeclStmt( newTemp ) );
+					temp = newTemp;
+				}
+				// update diff so that remaining code works out correctly
+				castExpr->arg = new VariableExpr( temp );
+				PRINT( std::cerr << "update cast to: " << castExpr << std::endl; )
+				srcType = castExpr->arg->result;
+				depth2 = srcType->referenceDepth();
+				diff = depth1 - depth2;
+				assert( diff == 1 );
+			}
+
+			// handle conversion between different depths
+			PRINT (
+				if ( depth1 || depth2 ) {
+					std::cerr << "destType: " << destType << " / srcType: " << srcType << std::endl;
+					std::cerr << "depth: " << depth1 << " / " << depth2 << std::endl;
+				}
+			)
+			if ( diff > 0 ) {
+				// conversion to type with more depth (e.g. int & -> int &&): add address-of for each level of difference
+				Expression * ret = castExpr->arg;
+				for ( int i = 0; i < diff; ++i ) {
+					ret = new AddressExpr( ret );
+				}
+				if ( srcType->get_lvalue() && srcType->get_qualifiers() != strict_dynamic_cast<ReferenceType *>( destType )->base->get_qualifiers() ) {
+					// must keep cast if cast-to type is different from the actual type
+					castExpr->arg = ret;
 					return castExpr;
-				} else if ( castExpr->arg->result->get_lvalue() ) {
-					// conversion from lvalue to reference
-					// xxx - keep cast, but turn into pointer cast??
-					// xxx - memory
-					PRINT(
-						std::cerr << "convert lvalue to reference -- &" << std::endl;
-						std::cerr << castExpr->arg << std::endl;
-					)
-					AddressExpr * ret = new AddressExpr( castExpr->arg );
-					if ( refType->base->get_qualifiers() != castExpr->arg->result->get_qualifiers() ) {
-						// must keep cast if cast-to type is different from the actual type
-						castExpr->arg = ret;
-						return castExpr;
-					}
-					ret->env = castExpr->env;
-					delete ret->result;
-					ret->result = castExpr->result;
-					castExpr->env = nullptr;
-					castExpr->arg = nullptr;
-					castExpr->result = nullptr;
-					delete castExpr;
-					return ret;
-				} else {
-					// rvalue to reference conversion -- introduce temporary
-				}
-				assertf( false, "Only conversions to reference from lvalue are currently supported: %s", toString( castExpr ).c_str() );
-			} else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( castExpr->arg->result ) ) {
-				(void)refType;
-				// conversion from reference to rvalue
-				PRINT(
-					std::cerr << "convert reference to rvalue -- *" << std::endl;
-					std::cerr << "was = " << castExpr << std::endl;
-				)
+				}
+				ret->env = castExpr->env;
+				delete ret->result;
+				ret->result = castExpr->result;
+				castExpr->env = nullptr;
+				castExpr->arg = nullptr;
+				castExpr->result = nullptr;
+				delete castExpr;
+				return ret;
+			} else if ( diff < 0 ) {
+				// conversion to type with less depth (e.g. int && -> int &): add dereferences for each level of difference
+				diff = -diff; // care only about magnitude now
 				Expression * ret = castExpr->arg;
-				TypeSubstitution * env = castExpr->env;
-				castExpr->set_env( nullptr );
-				if ( ! isIntrinsicReference( ret ) ) {
-					// dereference if not already dereferenced
+				for ( int i = 0; i < diff; ++i ) {
 					ret = mkDeref( ret );
 				}
-				if ( ResolvExpr::typesCompatibleIgnoreQualifiers( castExpr->result, castExpr->arg->result->stripReferences(), SymTab::Indexer() ) ) {
-					// can remove cast if types are compatible, changing expression type to value type
-					ret->result = castExpr->result->clone();
-					ret->result->set_lvalue( true );  // ensure result is lvalue
-					castExpr->arg = nullptr;
-					delete castExpr;
-				} else {
+				if ( ! ResolvExpr::typesCompatibleIgnoreQualifiers( destType->stripReferences(), srcType->stripReferences(), SymTab::Indexer() ) ) {
 					// must keep cast if types are different
 					castExpr->arg = ret;
-					ret = castExpr;
-				}
-				ret->set_env( env );
-				PRINT( std::cerr << "now: " << ret << std::endl; )
-				return ret;
-			}
-			return castExpr;
+					return castExpr;
+				}
+				ret->env = castExpr->env;
+				delete ret->result;
+				ret->result = castExpr->result;
+				ret->result->set_lvalue( true ); // ensure result is lvalue
+				castExpr->env = nullptr;
+				castExpr->arg = nullptr;
+				castExpr->result = nullptr;
+				delete castExpr;
+				return ret;
+			} else {
+				assert( diff == 0 );
+				// conversion between references of the same depth
+				return castExpr;
+			}
 		}
 
 		Type * ReferenceTypeElimination::postmutate( ReferenceType * refType ) {
-			Type * base = refType->get_base();
+			Type * base = refType->base;
 			Type::Qualifiers qualifiers = refType->get_qualifiers();
-			refType->set_base( nullptr );
+			refType->base = nullptr;
 			delete refType;
 			return new PointerType( qualifiers, base );
@@ -414,18 +384,18 @@
 		Expression * GeneralizedLvalue::applyTransformation( Expression * expr, Expression * arg, Func mkExpr ) {
 			if ( CommaExpr * commaExpr = dynamic_cast< CommaExpr * >( arg ) ) {
-				Expression * arg1 = commaExpr->get_arg1()->clone();
-				Expression * arg2 = commaExpr->get_arg2()->clone();
+				Expression * arg1 = commaExpr->arg1->clone();
+				Expression * arg2 = commaExpr->arg2->clone();
 				Expression * ret = new CommaExpr( arg1, mkExpr( arg2 )->acceptMutator( *visitor ) );
-				ret->set_env( expr->get_env() );
-				expr->set_env( nullptr );
+				ret->env = expr->env;
+				expr->env = nullptr;
 				delete expr;
 				return ret;
 			} else if ( ConditionalExpr * condExpr = dynamic_cast< ConditionalExpr * >( arg ) ) {
-				Expression * arg1 = condExpr->get_arg1()->clone();
-				Expression * arg2 = condExpr->get_arg2()->clone();
-				Expression * arg3 = condExpr->get_arg3()->clone();
+				Expression * arg1 = condExpr->arg1->clone();
+				Expression * arg2 = condExpr->arg2->clone();
+				Expression * arg3 = condExpr->arg3->clone();
 				ConditionalExpr * ret = new ConditionalExpr( arg1, mkExpr( arg2 )->acceptMutator( *visitor ), mkExpr( arg3 )->acceptMutator( *visitor ) );
-				ret->set_env( expr->get_env() );
-				expr->set_env( nullptr );
+				ret->env = expr->env;
+				expr->env = nullptr;
 				delete expr;
 
@@ -436,6 +406,6 @@
 				AssertionSet needAssertions, haveAssertions;
 				OpenVarSet openVars;
-				unify( ret->get_arg2()->get_result(), ret->get_arg3()->get_result(), newEnv, needAssertions, haveAssertions, openVars, SymTab::Indexer(), commonType );
-				ret->set_result( commonType ? commonType : ret->get_arg2()->get_result()->clone() );
+				unify( ret->arg2->result, ret->arg3->result, newEnv, needAssertions, haveAssertions, openVars, SymTab::Indexer(), commonType );
+				ret->result = commonType ? commonType : ret->arg2->result->clone();
 				return ret;
 			}
@@ -444,13 +414,13 @@
 
 		Expression * GeneralizedLvalue::postmutate( MemberExpr * memExpr ) {
-			return applyTransformation( memExpr, memExpr->get_aggregate(), [=]( Expression * aggr ) { return new MemberExpr( memExpr->get_member(), aggr ); } );
+			return applyTransformation( memExpr, memExpr->aggregate, [=]( Expression * aggr ) { return new MemberExpr( memExpr->member, aggr ); } );
 		}
 
 		Expression * GeneralizedLvalue::postmutate( AddressExpr * addrExpr ) {
-			return applyTransformation( addrExpr, addrExpr->get_arg(), []( Expression * arg ) { return new AddressExpr( arg ); } );
+			return applyTransformation( addrExpr, addrExpr->arg, []( Expression * arg ) { return new AddressExpr( arg ); } );
 		}
 
 		Expression * CollapseAddrDeref::postmutate( AddressExpr * addrExpr ) {
-			Expression * arg = addrExpr->get_arg();
+			Expression * arg = addrExpr->arg;
 			if ( isIntrinsicReference( arg ) ) {
 				std::string fname = InitTweak::getFunctionName( arg );
@@ -458,7 +428,7 @@
 					Expression *& arg0 = InitTweak::getCallArg( arg, 0 );
 					Expression * ret = arg0;
-					ret->set_env( addrExpr->get_env() );
+					ret->set_env( addrExpr->env );
 					arg0 = nullptr;
-					addrExpr->set_env( nullptr );
+					addrExpr->env = nullptr;
 					delete addrExpr;
 					return ret;
@@ -487,8 +457,8 @@
 					// }
 					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 );
+						Expression * ret = addrExpr->arg;
+						ret->env = appExpr->env;
+						addrExpr->arg = nullptr;
+						appExpr->env = nullptr;
 						delete appExpr;
 						return ret;
Index: src/tests/.expect/references.txt
===================================================================
--- src/tests/.expect/references.txt	(revision c5ce0ecd56e67e949d0b059b405df1120ed18b85)
+++ src/tests/.expect/references.txt	(revision d2034b4821bf389f33b55c7285d2540e23596684)
@@ -28,4 +28,8 @@
 Destructing a Y
 Destructing a Y
+3 3
+3
+3
+3 9 { 1, 7 }, [1, 2, 3]
 Destructing a Y
 Destructing a Y
Index: src/tests/references.c
===================================================================
--- src/tests/references.c	(revision c5ce0ecd56e67e949d0b059b405df1120ed18b85)
+++ src/tests/references.c	(revision d2034b4821bf389f33b55c7285d2540e23596684)
@@ -49,7 +49,16 @@
 		&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
+	// typeof( ar[1] ) p;                  // is int, i.e., the type of referenced object
+	// typeof( &ar[1] ) q;                 // is int &, i.e., the type of reference
+	// sizeof( ar[1] ) == sizeof( int );   // is true, i.e., the size of referenced object
+	// sizeof( &ar[1] ) == sizeof( int *); // is true, i.e., the size of a reference
 
 	// test that basic reference properties are true - r1 should be an alias for x
@@ -76,5 +85,26 @@
 	&z1.r = &z1r;
 	&z2.r = &z2r;
+
 	z1 = z2;
+
+	// test rvalue-to-reference conversion
+	{
+		struct S { double x, y; };
+		void f( int & i, int & j, S & s, int v[] ) {
+			printf("%d %d { %g, %g }, [%d, %d, %d]\n", i, j, s.[x, y], v[0], v[1], v[2]);
+		}
+		void g(int & i) { printf("%d\n", i); }
+		void h(int &&& i) { printf("%d\n", i); }
+
+		int &&& r = 3;  // rvalue to reference
+		int i = r;
+		printf("%d %d\n", i, r);  // both 3
+
+		g( 3 );          // rvalue to reference
+		h( (int &&&)3 ); // rvalue to reference
+
+		int a = 5, b = 4;
+		f( 3, a + b, (S){ 1.0, 7.0 }, (int [3]){ 1, 2, 3 } ); // two rvalue to reference
+	}
 }
 
