Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 9e72dbb75640618596acfcb92156edb505a935dc)
+++ src/Makefile.in	(revision 4615ac81401b8a87620dad09deac63435bd06109)
@@ -231,5 +231,5 @@
 	SynTree/Initializer.$(OBJEXT) \
 	SynTree/TypeSubstitution.$(OBJEXT) SynTree/Attribute.$(OBJEXT) \
-	SynTree/DeclReplacer.$(OBJEXT)
+	SynTree/DeclReplacer.$(OBJEXT) SynTree/TopLvalue.$(OBJEXT)
 am__objects_8 = CompilationState.$(OBJEXT) $(am__objects_1) \
 	$(am__objects_2) Concurrency/Keywords.$(OBJEXT) \
@@ -694,5 +694,6 @@
       SynTree/TypeSubstitution.cc \
       SynTree/Attribute.cc \
-      SynTree/DeclReplacer.cc
+      SynTree/DeclReplacer.cc \
+      SynTree/TopLvalue.cc
 
 
@@ -1023,4 +1024,6 @@
 SynTree/DeclReplacer.$(OBJEXT): SynTree/$(am__dirstamp) \
 	SynTree/$(DEPDIR)/$(am__dirstamp)
+SynTree/TopLvalue.$(OBJEXT): SynTree/$(am__dirstamp) \
+	SynTree/$(DEPDIR)/$(am__dirstamp)
 Tuples/$(am__dirstamp):
 	@$(MKDIR_P) Tuples
@@ -1333,4 +1336,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/ReferenceType.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/Statement.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/TopLvalue.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/TupleExpr.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/TupleType.Po@am__quote@
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 9e72dbb75640618596acfcb92156edb505a935dc)
+++ src/SymTab/Validate.cc	(revision 4615ac81401b8a87620dad09deac63435bd06109)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 21:50:04 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Aug 28 13:47:23 2017
-// Update Count     : 359
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Aug  7 6:42:00 2019
+// Update Count     : 360
 //
 
@@ -81,4 +81,5 @@
 #include "SynTree/Label.h"             // for operator==, Label
 #include "SynTree/Mutator.h"           // for Mutator
+#include "SynTree/TopLvalue.h"         // for assertTopLvalue, clearInnerLvalue
 #include "SynTree/Type.h"              // for Type, TypeInstType, EnumInstType
 #include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
@@ -308,4 +309,5 @@
 		PassVisitor<FixQualifiedTypes> fixQual;
 
+		assertTopLvalue( translationUnit );
 		{
 			Stats::Heap::newPass("validate-A");
@@ -316,20 +318,27 @@
 			acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling
 		}
+		assertTopLvalue( translationUnit );
 		{
 			Stats::Heap::newPass("validate-B");
 			Stats::Time::BlockGuard guard("validate-B");
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Link Reference To Types", [&]() {
 				acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions
 			});
+			clearInnerLvalue( translationUnit );
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Fix Qualified Types", [&]() {
 				mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes_old, because aggregate members are accessed
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Hoist Structs", [&]() {
 				HoistStruct::hoistStruct( translationUnit ); // must happen after EliminateTypedef, so that aggregate typedefs occur in the correct order
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Eliminate Typedefs", [&]() {
 				EliminateTypedef::eliminateTypedef( translationUnit ); //
 			});
 		}
+		assertTopLvalue( translationUnit );
 		{
 			Stats::Heap::newPass("validate-C");
@@ -340,55 +349,77 @@
 			InitTweak::fixReturnStatements( translationUnit ); // must happen before autogen
 		}
+		assertTopLvalue( translationUnit );
 		{
 			Stats::Heap::newPass("validate-D");
 			Stats::Time::BlockGuard guard("validate-D");
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Apply Concurrent Keywords", [&]() {
 				Concurrency::applyKeywords( translationUnit );
 			});
+			clearInnerLvalue( translationUnit );
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Forall Pointer Decay", [&]() {
 				acceptAll( translationUnit, fpd ); // must happen before autogenerateRoutines, after Concurrency::applyKeywords because uniqueIds must be set on declaration before resolution
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Hoist Control Declarations", [&]() {
 				ControlStruct::hoistControlDecls( translationUnit );  // hoist initialization out of for statements; must happen before autogenerateRoutines
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Generate Autogen routines", [&]() {
 				autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecay_old
 			});
-		}
+			clearInnerLvalue( translationUnit );
+		}
+		assertTopLvalue( translationUnit );
 		{
 			Stats::Heap::newPass("validate-E");
 			Stats::Time::BlockGuard guard("validate-E");
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Implement Mutex Func", [&]() {
 				Concurrency::implementMutexFuncs( translationUnit );
 			});
+			clearInnerLvalue( translationUnit );
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Implement Thread Start", [&]() {
 				Concurrency::implementThreadStarter( translationUnit );
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Compound Literal", [&]() {
 				mutateAll( translationUnit, compoundliteral );
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Resolve With Expressions", [&]() {
 				ResolvExpr::resolveWithExprs( translationUnit ); // must happen before FixObjectType because user-code is resolved and may contain with variables
 			});
-		}
+			clearInnerLvalue( translationUnit );
+		}
+		assertTopLvalue( translationUnit );
 		{
 			Stats::Heap::newPass("validate-F");
 			Stats::Time::BlockGuard guard("validate-F");
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Fix Object Type", [&]() {
 				FixObjectType::fix( translationUnit );
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Array Length", [&]() {
 				ArrayLength::computeLength( translationUnit );
 			});
+			clearInnerLvalue( translationUnit );
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Find Special Declarations", [&]() {
 				Validate::findSpecialDecls( translationUnit );
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Fix Label Address", [&]() {
 				mutateAll( translationUnit, labelAddrFixer );
 			});
+			assertTopLvalue( translationUnit );
 			Stats::Time::TimeBlock("Handle Attributes", [&]() {
 				Validate::handleAttributes( translationUnit );
 			});
 		}
+		assertTopLvalue( translationUnit );
 	}
 
Index: src/SynTree/TopLvalue.cc
===================================================================
--- src/SynTree/TopLvalue.cc	(revision 4615ac81401b8a87620dad09deac63435bd06109)
+++ src/SynTree/TopLvalue.cc	(revision 4615ac81401b8a87620dad09deac63435bd06109)
@@ -0,0 +1,132 @@
+//
+// 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.
+//
+// TopLvalue.cc -- Check and force that lvalue is only at the top of types.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Jul 31 15:49:00 2019
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Aug  7 15:36:00 2019
+// Update Count     : 0
+//
+
+#include <iostream>
+
+#include "Common/PassVisitor.h"
+
+namespace {
+	class TopLvalue : public WithGuards {
+		bool inType = false;
+	public:
+		void previsit( const BaseSyntaxNode * ) {
+			if ( inType ) {
+				GuardValue( inType );
+				inType = false;
+			}
+		}
+
+		void previsit( const Type * type ) {
+			if ( inType ) {
+				assert( !type->get_lvalue() );
+			} else {
+				GuardValue( inType );
+				inType = true;
+			}
+		}
+
+	};
+
+	class ClearLvalue : public WithGuards {
+		bool inType = false;
+	public:
+		void previsit( BaseSyntaxNode * ) {
+			if ( inType ) {
+				GuardValue( inType );
+				inType = false;
+			}
+		}
+
+		void previsit( Type * type ) {
+			if ( !inType ) {
+				GuardValue( inType );
+				inType = true;
+			} else if ( type->get_lvalue() ) {
+				type->set_lvalue( false );
+			}
+		}
+	};
+
+	class TopLvaluePrint : public WithGuards, public WithShortCircuiting {
+		bool failed = false;
+		bool inType = false;
+		bool typeTop = false;
+	public:
+		bool failedAny = false;
+		void previsit() {
+			if ( failed ) {
+				visit_children = false;
+			} else if ( typeTop ) {
+				GuardValue( typeTop );
+				typeTop = false;
+			}
+		}
+
+		void previsit( const BaseSyntaxNode * ) {
+			previsit();
+			if ( inType ) {
+				GuardValue( inType );
+				inType = false;
+			}
+		}
+
+		void previsit( const Type * type ) {
+			previsit();
+			if ( inType ) {
+				if ( type->get_lvalue() ) {
+					failed = true;
+					failedAny = true;
+					visit_children = false;
+					std::cout << type->location << std::endl;
+				}
+				//assert( !type->get_lvalue() );
+			} else {
+				GuardValue( inType );
+				inType = true;
+				typeTop = true;
+			}
+		}
+
+		void postvisit( const Type * type ) {
+			if ( typeTop ) {
+				if ( failed ) {
+					std::cout << type->location << std::endl;
+					type->print( std::cout );
+					//assert( !failed );
+					failed = false;
+				}
+				typeTop = false;
+			}
+		}
+	};
+}
+
+void assertTopLvalue( const std::list< Declaration * > & translationUnit ) {
+	PassVisitor< TopLvaluePrint > visitor;
+	acceptAll( translationUnit, visitor );
+	assert( !visitor.pass.failedAny );
+}
+
+void clearInnerLvalue( std::list< Declaration * > & translationUnit ) {
+	PassVisitor< ClearLvalue > visitor;
+	acceptAll( translationUnit, visitor );
+}
+
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SynTree/TopLvalue.h
===================================================================
--- src/SynTree/TopLvalue.h	(revision 4615ac81401b8a87620dad09deac63435bd06109)
+++ src/SynTree/TopLvalue.h	(revision 4615ac81401b8a87620dad09deac63435bd06109)
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+// TopLvalue.h -- Check and force that lvalue is only at the top of types.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Jul 31 16:04:00 2019
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Aug  7 15:26:00 2019
+// Update Count     : 0
+//
+
+#include <list>
+class Declaration;
+
+void assertTopLvalue( const std::list< Declaration * > & translationUnit );
+/* Assert that all lvalue qualifiers are set on the top level.
+ *
+ * Does not return if the test fails.
+ */
+
+void clearInnerLvalue( std::list< Declaration * > & translationUnit );
+/* Make all types that are not at the top level rvalues (not-lvalues).
+ */
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
+
Index: src/SynTree/module.mk
===================================================================
--- src/SynTree/module.mk	(revision 9e72dbb75640618596acfcb92156edb505a935dc)
+++ src/SynTree/module.mk	(revision 4615ac81401b8a87620dad09deac63435bd06109)
@@ -49,5 +49,6 @@
       SynTree/TypeSubstitution.cc \
       SynTree/Attribute.cc \
-      SynTree/DeclReplacer.cc
+      SynTree/DeclReplacer.cc \
+      SynTree/TopLvalue.cc
 
 SRC += $(SRC_SYNTREE)
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 9e72dbb75640618596acfcb92156edb505a935dc)
+++ src/main.cc	(revision 4615ac81401b8a87620dad09deac63435bd06109)
@@ -59,8 +59,10 @@
 #include "ResolvExpr/Resolver.h"            // for resolve
 #include "SymTab/Validate.h"                // for validate
+#include "SynTree/TopLvalue.h"              // for assertTopLvalue, clearInn...
 #include "SynTree/Declaration.h"            // for Declaration
 #include "SynTree/Visitor.h"                // for acceptAll
 #include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
 #include "Virtual/ExpandCasts.h"            // for expandCasts
+
 
 using namespace std;
@@ -257,4 +259,8 @@
 		Stats::Time::StopBlock();
 
+		//std::cerr << "Post-Parse Check" << std::endl;
+		clearInnerLvalue( translationUnit );
+		assertTopLvalue( translationUnit );
+
 		// add the assignment statement after the initialization of a type parameter
 		PASS( "Validate", SymTab::validate( translationUnit, symtabp ) );
@@ -275,8 +281,13 @@
 		} // if
 
+		assertTopLvalue( translationUnit );
 		PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
+		assertTopLvalue( translationUnit );
 		PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
+		assertTopLvalue( translationUnit );
 		PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
+		assertTopLvalue( translationUnit );
 		PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) );
+		assertTopLvalue( translationUnit );
 		if ( libcfap ) {
 			// generate the bodies of cfa library functions
@@ -302,4 +313,6 @@
 		} // if
 
+		assertTopLvalue( translationUnit );
+
 		PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
 		if ( exprp ) {
@@ -308,6 +321,11 @@
 		} // if
 
+		clearInnerLvalue( translationUnit );
+		assertTopLvalue( translationUnit );
+
 		// fix ObjectDecl - replaces ConstructorInit nodes
 		PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
+		clearInnerLvalue( translationUnit );
+		assertTopLvalue( translationUnit );
 		if ( ctorinitp ) {
 			dump ( translationUnit );
@@ -316,12 +334,19 @@
 
 		PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
+		assertTopLvalue( translationUnit );
 
 		PASS( "Translate EHM" , ControlStruct::translateEHM( translationUnit ) );
+		assertTopLvalue( translationUnit );
 
 		PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) );
+		clearInnerLvalue( translationUnit );
+		assertTopLvalue( translationUnit );
 
 		PASS( "Convert Specializations",  GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded
+		clearInnerLvalue( translationUnit );
+		assertTopLvalue( translationUnit );
 
 		PASS( "Expand Tuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this?
+		assertTopLvalue( translationUnit );
 
 		if ( tuplep ) {
@@ -331,4 +356,5 @@
 
 		PASS( "Virtual Expand Casts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM
+		assertTopLvalue( translationUnit );
 
 		PASS( "Instantiate Generics", GenPoly::instantiateGeneric( translationUnit ) );
@@ -337,6 +363,9 @@
 			return EXIT_SUCCESS;
 		} // if
+		clearInnerLvalue( translationUnit );
+		assertTopLvalue( translationUnit );
 		PASS( "Convert L-Value", GenPoly::convertLvalue( translationUnit ) );
-
+		clearInnerLvalue( translationUnit );
+		assertTopLvalue( translationUnit );
 
 		if ( bboxp ) {
@@ -345,4 +374,6 @@
 		} // if
 		PASS( "Box", GenPoly::box( translationUnit ) );
+		clearInnerLvalue( translationUnit );
+		assertTopLvalue( translationUnit );
 
 		if ( bcodegenp ) {
@@ -356,4 +387,5 @@
 
 		CodeTools::fillLocations( translationUnit );
+		assertTopLvalue( translationUnit );
 		PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
 
