Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision c36298dc6ce35031df4fda23fb859c772e2c6f5f)
+++ src/AST/Expr.cpp	(revision cf32116a7c8c54e0d0839465e3e60ca0be290dbc)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 15 17:00:00 2019
 // Last Modified By : Andrew Beach
-// Created On       : Thr Jun 13 13:38:00 2019
-// Update Count     : 2
+// Created On       : Thr Jun 26 12:12:00 2019
+// Update Count     : 3
 //
 
@@ -20,5 +20,8 @@
 #include <vector>
 
+#include "Copy.hpp"                // for shallowCopy
+#include "Eval.hpp"                // for call
 #include "GenericSubstitution.hpp"
+#include "LinkageSpec.hpp"
 #include "Stmt.hpp"
 #include "Type.hpp"
@@ -27,9 +30,18 @@
 #include "Common/SemanticError.h"
 #include "GenPoly/Lvalue.h"        // for referencesPermissable
-#include "InitTweak/InitTweak.h"   // for getPointerBase
+#include "InitTweak/InitTweak.h"   // for getFunction, getPointerBase
 #include "ResolvExpr/typeops.h"    // for extractResultType
 #include "Tuples/Tuples.h"         // for makeTupleType
 
 namespace ast {
+
+namespace {
+	std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
+}
+
+// --- Expr
+bool Expr::get_lvalue() const {
+	return false;
+}
 
 // --- ApplicationExpr
@@ -46,4 +58,11 @@
 }
 
+bool ApplicationExpr::get_lvalue() const {
+	if ( const DeclWithType * func = InitTweak::getFunction( this ) ) {
+		return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
+	}
+	return false;
+}
+
 // --- UntypedExpr
 
@@ -51,7 +70,5 @@
 	assert( arg );
 
-	UntypedExpr * ret = new UntypedExpr{
-		loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
-	};
+	UntypedExpr * ret = call( loc, "*?", arg );
 	if ( const Type * ty = arg->result ) {
 		const Type * base = InitTweak::getPointerBase( ty );
@@ -71,10 +88,13 @@
 }
 
+bool UntypedExpr::get_lvalue() const {
+	std::string fname = InitTweak::getFunctionName( this );
+	return lvalueFunctionNames.count( fname );
+}
+
 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ) {
 	assert( lhs && rhs );
 
-	UntypedExpr * ret = new UntypedExpr{
-		loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
-	};
+	UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
 	if ( lhs->result && rhs->result ) {
 		// if both expressions are typed, assumes that this assignment is a C bitwise assignment,
@@ -108,5 +128,5 @@
 AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) {
 	if ( arg->result ) {
-		if ( arg->result->is_lvalue() ) {
+		if ( arg->get_lvalue() ) {
 			// lvalue, retains all levels of reference, and gains a pointer inside the references
 			Type * res = addrType( arg->result );
@@ -139,4 +159,9 @@
 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
 
+bool CastExpr::get_lvalue() const {
+	// This is actually wrong by C, but it works with our current set-up.
+	return arg->get_lvalue();
+}
+
 // --- KeywordCastExpr
 
@@ -152,4 +177,10 @@
 }
 
+// --- UntypedMemberExpr
+
+bool UntypedMemberExpr::get_lvalue() const {
+	return aggregate->get_lvalue();
+}
+
 // --- MemberExpr
 
@@ -160,6 +191,41 @@
 	assert( aggregate->result );
 
-	// take ownership of member type
-	result = mem->get_type();
+	// Deep copy on result type avoids mutation on transitively multiply referenced object.
+	//
+	// Example, adapted from parts of builtins and bootloader:
+	//
+	// forall(dtype T)
+	// struct __Destructor {
+	//   T * object;
+	//   void (*dtor)(T *);
+	// };
+	//
+	// forall(dtype S)
+	// void foo(__Destructor(S) &d) {
+	//   if (d.dtor) {  // here
+	//   }
+	// }
+	//
+	// Let e be the "d.dtor" guard espression, which is MemberExpr after resolve.  Let d be the
+	// declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level
+	// declaration of __Destructor.  Consider the types e.result and d.type.  In the old AST, one
+	// is a clone of the other.  Ordinary new-AST use would set them up as a multiply-referenced
+	// object.
+	//
+	// e.result: PointerType
+	// .base: FunctionType
+	// .params.front(): ObjectDecl, the anonymous parameter of type T*
+	// .type: PointerType
+	// .base: TypeInstType
+	// let x = that
+	// let y = similar, except start from d.type
+	//
+	// Consider two code lines down, genericSubstitution(...).apply(result).
+	//
+	// Applying this chosen-candidate's type substitution means modifying x, substituting
+	// S for T.  This mutation should affect x and not y.
+
+	result = deepCopy(mem->get_type());
+
 	// substitute aggregate generic parameters into member type
 	genericSubstitution( aggregate->result ).apply( result );
@@ -168,4 +234,18 @@
 }
 
+MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
+    MemberExpr::NoOpConstruction overloadSelector )
+: Expr( loc ), member( mem ), aggregate( agg ) {
+	assert( member );
+	assert( aggregate );
+	assert( aggregate->result );
+	(void) overloadSelector;
+}
+
+bool MemberExpr::get_lvalue() const {
+	// This is actually wrong by C, but it works with our current set-up.
+	return true;
+}
+
 // --- VariableExpr
 
@@ -177,6 +257,12 @@
 	assert( var );
 	assert( var->get_type() );
-	result = var->get_type();
-	add_qualifiers( result, CV::Lvalue );
+	auto r = shallowCopy( var->get_type() );
+	r->qualifiers |= CV::Lvalue;
+	result = r;
+}
+
+bool VariableExpr::get_lvalue() const {
+	// It isn't always an lvalue, but it is never an rvalue.
+	return true;
 }
 
@@ -265,4 +351,11 @@
 : Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
 
+// --- CommaExpr
+bool CommaExpr::get_lvalue() const {
+	// This is wrong by C, but the current implementation uses it.
+	// (ex: Specialize, Lvalue and Box)
+	return arg2->get_lvalue();
+}
+
 // --- ConstructorExpr
 
@@ -286,4 +379,8 @@
 }
 
+bool CompoundLiteralExpr::get_lvalue() const {
+	return true;
+}
+
 // --- TupleExpr
 
@@ -301,4 +398,8 @@
 	result = type->types[ index ];
 	add_qualifiers( result, CV::Lvalue );
+}
+
+bool TupleIndexExpr::get_lvalue() const {
+	return tuple->get_lvalue();
 }
 
