Index: src/SynTree/AddressExpr.cc
===================================================================
--- src/SynTree/AddressExpr.cc	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/AddressExpr.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -21,7 +21,35 @@
 #include "Type.h"            // for PointerType, Type, Type::Qualifiers
 
+// 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() ) {
-		set_result( new PointerType( Type::Qualifiers(), arg->get_result()->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 {
+			// 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 );
 	}
 }
Index: src/SynTree/ApplicationExpr.cc
===================================================================
--- src/SynTree/ApplicationExpr.cc	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/ApplicationExpr.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -49,5 +49,5 @@
 }
 
-ApplicationExpr::ApplicationExpr( Expression *funcExpr, const std::list< Expression * > & argList ) : function( funcExpr ), args( argList ) {
+ApplicationExpr::ApplicationExpr( Expression *funcExpr, const std::list<Expression *> & args ) : function( funcExpr ), args( args ) {
 	PointerType *pointer = safe_dynamic_cast< PointerType* >( funcExpr->get_result() );
 	FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Declaration.h	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -109,5 +109,5 @@
 	virtual DeclarationWithType *acceptMutator( Mutator &m ) = 0;
 
-	virtual Type *get_type() const = 0;
+	virtual Type * get_type() const = 0;
 	virtual void set_type(Type *) = 0;
 
@@ -128,5 +128,5 @@
 	virtual ~ObjectDecl();
 
-	virtual Type *get_type() const { return type; }
+	virtual Type * get_type() const { return type; }
 	virtual void set_type(Type *newType) { type = newType; }
 
@@ -155,8 +155,8 @@
 	virtual ~FunctionDecl();
 
-	Type *get_type() const;
+	Type * get_type() const;
 	virtual void set_type(Type *);
 
-	FunctionType *get_functionType() const { return type; }
+	FunctionType * get_functionType() const { return type; }
 	void set_functionType( FunctionType *newValue ) { type = newValue; }
 	CompoundStmt *get_statements() const { return statements; }
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Expression.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -31,4 +31,5 @@
 #include "TypeSubstitution.h"        // for TypeSubstitution
 
+#include "GenPoly/Lvalue.h"
 
 Expression::Expression( Expression *_aname ) : result( 0 ), env( 0 ), argName( _aname ) {}
@@ -89,4 +90,10 @@
 }
 
+VariableExpr * VariableExpr::functionPointer( FunctionDecl * func ) {
+	VariableExpr * funcExpr = new VariableExpr( func );
+	funcExpr->set_result( new PointerType( Type::Qualifiers(), funcExpr->get_result() ) );
+	return funcExpr;
+}
+
 void VariableExpr::print( std::ostream &os, int indent ) const {
 	os << "Variable Expression: ";
@@ -149,5 +156,5 @@
 
 void AlignofExpr::print( std::ostream &os, int indent) const {
-	os << std::string( indent, ' ' ) << "Alignof Expression on: ";
+	os << "Alignof Expression on: ";
 
 	if (isType)
@@ -258,5 +265,5 @@
 
 void AttrExpr::print( std::ostream &os, int indent) const {
-	os << std::string( indent, ' ' ) << "Attr ";
+	os << "Attr ";
 	attr->print( os, indent + 2 );
 	if ( isType || expr ) {
@@ -357,5 +364,7 @@
 namespace {
 	TypeSubstitution makeSub( Type * t ) {
-		if ( StructInstType * aggInst = dynamic_cast< StructInstType * >( t ) ) {
+		if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( t ) ) {
+			return makeSub( refType->get_base() );
+		} else if ( StructInstType * aggInst = dynamic_cast< StructInstType * >( t ) ) {
 			return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->get_parameters().begin() );
 		} else if ( UnionInstType * aggInst = dynamic_cast< UnionInstType * >( t ) ) {
@@ -422,9 +431,13 @@
 	if ( Type * type = expr->get_result() ) {
 		Type * base = InitTweak::getPointerBase( type );
-		if ( ! base ) {
-			std::cerr << type << std::endl;
+		assertf( base, "expected pointer type in dereference (type was %s)", toString( type ).c_str() );
+		ret->set_result( base->clone() );
+		if ( GenPoly::referencesPermissable() ) {
+			// if references are still allowed in the AST, dereference returns a reference
+			ret->set_result( new ReferenceType( Type::Qualifiers(), ret->get_result() ) );
+		} else {
+			// references have been removed, in which case dereference returns an lvalue of the base type.
+			ret->get_result()->set_lvalue( true );
 		}
-		assertf( base, "expected pointer type in dereference\n" );
-		ret->set_result( maybeClone( base ) );
 	}
 	return ret;
@@ -490,5 +503,5 @@
 
 void LogicalExpr::print( std::ostream &os, int indent )const {
-	os << std::string( indent, ' ' ) << "Short-circuited operation (" << (isAnd?"and":"or") << ") on: ";
+	os << "Short-circuited operation (" << (isAnd?"and":"or") << ") on: ";
 	arg1->print(os);
 	os << " and ";
@@ -595,4 +608,5 @@
 CompoundLiteralExpr::CompoundLiteralExpr( Type * type, Initializer * initializer ) : initializer( initializer ) {
 	assert( type && initializer );
+	type->set_lvalue( true );
 	set_result( type );
 }
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Expression.h	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -284,4 +284,6 @@
 	void set_var( DeclarationWithType * newValue ) { var = newValue; }
 
+	static VariableExpr * functionPointer( FunctionDecl * decl );
+
 	virtual VariableExpr * clone() const { return new VariableExpr( * this ); }
 	virtual void accept( Visitor & v ) { v.visit( this ); }
Index: src/SynTree/Mutator.cc
===================================================================
--- src/SynTree/Mutator.cc	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Mutator.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -502,5 +502,11 @@
 }
 
-Type * Mutator::mutate( FunctionType *functionType ) {
+Type * Mutator::mutate( ReferenceType * refType ) {
+	mutateAll( refType->get_forall(), *this );
+	refType->set_base( maybeMutate( refType->get_base(), *this ) );
+	return refType;
+}
+
+Type * Mutator::mutate( FunctionType * functionType ) {
 	mutateAll( functionType->get_forall(), *this );
 	mutateAll( functionType->get_returnVals(), *this );
Index: src/SynTree/Mutator.h
===================================================================
--- src/SynTree/Mutator.h	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Mutator.h	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -93,4 +93,5 @@
 	virtual Type* mutate( PointerType *pointerType );
 	virtual Type* mutate( ArrayType *arrayType );
+	virtual Type* mutate( ReferenceType *refType );
 	virtual Type* mutate( FunctionType *functionType );
 	virtual Type* mutate( StructInstType *aggregateUseType );
Index: src/SynTree/ReferenceType.cc
===================================================================
--- src/SynTree/ReferenceType.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
+++ src/SynTree/ReferenceType.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -0,0 +1,49 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// PointerType.cc --
+//
+// Author           : Rob Schluntz
+// Created On       : Fri May 12 18:12:15 2017
+// Last Modified By : Rob Schluntz
+// Last Modified On : Fri May 12 18:12:15 2017
+// Update Count     : 1
+//
+
+#include "Type.h"
+#include "Expression.h"
+#include "Common/utility.h"
+
+ReferenceType::ReferenceType( const Type::Qualifiers &tq, Type *base, const std::list< Attribute * > & attributes )
+	: Type( tq, attributes ), base( base ) {
+	assertf( base, "Reference Type with a null base created." );
+}
+
+ReferenceType::ReferenceType( const ReferenceType &other )
+	: Type( other ), base( maybeClone( other.base ) ) {
+}
+
+ReferenceType::~ReferenceType() {
+	delete base;
+}
+
+int ReferenceType::referenceDepth() const {
+	return base->referenceDepth()+1;
+}
+
+void ReferenceType::print( std::ostream &os, int indent ) const {
+	Type::print( os, indent );
+	os << "reference to ";
+	if ( base ) {
+		base->print( os, indent );
+	} // if
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SynTree/SynTree.h
===================================================================
--- src/SynTree/SynTree.h	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/SynTree.h	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -102,4 +102,5 @@
 class PointerType;
 class ArrayType;
+class ReferenceType;
 class FunctionType;
 class ReferenceToType;
Index: src/SynTree/TupleExpr.cc
===================================================================
--- src/SynTree/TupleExpr.cc	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/TupleExpr.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -67,5 +67,6 @@
 	assertf( type->size() > index, "TupleIndexExpr index out of bounds: tuple size %d, requested index %d in expr %s", type->size(), index, toString( tuple ).c_str() );
 	set_result( (*std::next( type->get_types().begin(), index ))->clone() );
-	get_result()->set_lvalue( type->get_lvalue() );
+	// like MemberExpr, TupleIndexExpr is always an lvalue
+	get_result()->set_lvalue( true );
 }
 
Index: src/SynTree/Type.cc
===================================================================
--- src/SynTree/Type.cc	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Type.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -64,5 +64,5 @@
 const char * Type::QualifiersNames[] = { "const", "restrict", "volatile", "lvalue", "mutex", "_Atomic" };
 
-Type *Type::stripDeclarator() {
+Type * Type::stripDeclarator() {
 	Type * type = this;
 	while ( Type * at = InitTweak::getPointerBase( type ) ) {
@@ -71,4 +71,14 @@
 	return type;
 }
+
+Type * Type::stripReferences() {
+	Type * type = this;
+	while ( ReferenceType * ref = dynamic_cast<ReferenceType *>( type ) ) {
+		type = ref->get_base();
+	}
+	return type;
+}
+
+int Type::referenceDepth() const { return 0; }
 
 void Type::print( std::ostream &os, int indent ) const {
Index: src/SynTree/Type.h
===================================================================
--- src/SynTree/Type.h	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Type.h	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -168,5 +168,11 @@
 
 	/// return type without outer pointers and arrays
-	Type *stripDeclarator();
+	Type * stripDeclarator();
+
+	/// return type without outer references
+	Type * stripReferences();
+
+	/// return the number of references occuring consecutively on the outermost layer of this type (i.e. do not count references nested within other types)
+	virtual int referenceDepth() const;
 
 	virtual bool isComplete() const { return true; }
@@ -262,4 +268,6 @@
 	bool is_array() const { return isStatic || isVarLen || dimension; }
 
+	virtual bool isComplete() const { return ! isVarLen; }
+
 	virtual PointerType *clone() const { return new PointerType( *this ); }
 	virtual void accept( Visitor & v ) { v.visit( this ); }
@@ -296,4 +304,28 @@
 };
 
+class ReferenceType : public Type {
+public:
+	Type *base;
+
+	ReferenceType( const Type::Qualifiers & tq, Type *base, const std::list< Attribute * > & attributes = std::list< Attribute * >() );
+	ReferenceType( const ReferenceType & );
+	virtual ~ReferenceType();
+
+	Type *get_base() { return base; }
+	void set_base( Type *newValue ) { base = newValue; }
+
+	virtual int referenceDepth() const;
+
+	// Since reference types act like value types, their size is the size of the base.
+	// This makes it simple to cast the empty tuple to a reference type, since casts that increase
+	// the number of values are disallowed.
+	virtual unsigned size() const { return base->size(); }
+
+	virtual ReferenceType *clone() const { return new ReferenceType( *this ); }
+	virtual void accept( Visitor & v ) { v.visit( this ); }
+	virtual Type *acceptMutator( Mutator & m ) { return m.mutate( this ); }
+	virtual void print( std::ostream & os, int indent = 0 ) const;
+};
+
 class FunctionType : public Type {
   public:
Index: src/SynTree/TypeExpr.cc
===================================================================
--- src/SynTree/TypeExpr.cc	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/TypeExpr.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// TypeExpr.cc -- 
+// TypeExpr.cc --
 //
 // Author           : Richard C. Bilson
Index: src/SynTree/TypeSubstitution.h
===================================================================
--- src/SynTree/TypeSubstitution.h	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/TypeSubstitution.h	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -117,5 +117,5 @@
 				} // if
 			} else {
-				throw SemanticError( "Attempt to provide non-type parameter for type parameter", formal );
+				throw SemanticError( toString( "Attempt to provide non-type parameter: ", toString( *actualIt ).c_str(), " for type parameter " ), formal );
 			} // if
 		} else {
Index: src/SynTree/Visitor.cc
===================================================================
--- src/SynTree/Visitor.cc	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Visitor.cc	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -389,4 +389,5 @@
 void Visitor::visit( PointerType *pointerType ) {
 	acceptAll( pointerType->get_forall(), *this );
+	// xxx - should PointerType visit/mutate dimension?
 	maybeAccept( pointerType->get_base(), *this );
 }
@@ -396,4 +397,9 @@
 	maybeAccept( arrayType->get_dimension(), *this );
 	maybeAccept( arrayType->get_base(), *this );
+}
+
+void Visitor::visit( ReferenceType *refType ) {
+	acceptAll( refType->get_forall(), *this );
+	maybeAccept( refType->get_base(), *this );
 }
 
Index: src/SynTree/Visitor.h
===================================================================
--- src/SynTree/Visitor.h	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/Visitor.h	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -95,4 +95,5 @@
 	virtual void visit( PointerType *pointerType );
 	virtual void visit( ArrayType *arrayType );
+	virtual void visit( ReferenceType *refType );
 	virtual void visit( FunctionType *functionType );
 	virtual void visit( StructInstType *aggregateUseType );
Index: src/SynTree/module.mk
===================================================================
--- src/SynTree/module.mk	(revision 135b43118e38aa40c2f0cbfa16829e4b41313af7)
+++ src/SynTree/module.mk	(revision 212c421ef409d6b6cfdc46f15d088a510a868f95)
@@ -20,4 +20,5 @@
        SynTree/PointerType.cc \
        SynTree/ArrayType.cc \
+       SynTree/ReferenceType.cc \
        SynTree/FunctionType.cc \
        SynTree/ReferenceToType.cc \
