Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 4a161bec79efbca86c77e4b7538c59ce8114edbe)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision c71b2568066cb39013d366dd0195e430de881e0e)
@@ -95,4 +95,6 @@
 		void postvisit( StmtExpr * stmtExpr );
 		void postvisit( UntypedInitExpr * initExpr );
+		void postvisit( InitExpr * initExpr );
+		void postvisit( DeletedExpr * delExpr );
 
 		/// Adds alternatives for anonymous members
@@ -120,19 +122,4 @@
 		Type *& targetType;
 	};
-
-	Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
-		CastExpr *castToVoid = new CastExpr( expr );
-
-		AlternativeFinder finder( indexer, env );
-		finder.findWithAdjustment( castToVoid );
-
-		// it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
-		// interpretations, an exception has already been thrown.
-		assert( finder.get_alternatives().size() == 1 );
-		CastExpr *newExpr = dynamic_cast< CastExpr* >( finder.get_alternatives().front().expr );
-		assert( newExpr );
-		env = finder.get_alternatives().front().env;
-		return newExpr->get_arg()->clone();
-	}
 
 	Cost sumCost( const AltList &in ) {
@@ -1751,4 +1738,12 @@
 		findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
 	}
+
+	void AlternativeFinder::Finder::postvisit( InitExpr * ) {
+		assertf( false, "AlternativeFinder should never see a resolved InitExpr." );
+	}
+
+	void AlternativeFinder::Finder::postvisit( DeletedExpr * ) {
+		assertf( false, "AlternativeFinder should never see a DeletedExpr." );
+	}
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 4a161bec79efbca86c77e4b7538c59ce8114edbe)
+++ src/ResolvExpr/Resolver.cc	(revision c71b2568066cb39013d366dd0195e430de881e0e)
@@ -105,8 +105,22 @@
 	}
 
-	// used in resolveTypeof
-	Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer ) {
-		TypeEnvironment env;
-		return resolveInVoidContext( expr, indexer, env );
+	namespace {
+		struct DeleteFinder : public WithShortCircuiting	{
+			DeletedExpr * delExpr = nullptr;
+			void previsit( DeletedExpr * expr ) {
+				if ( delExpr ) visit_children = false;
+				else delExpr = expr;
+			}
+
+			void previsit( Expression * ) {
+				if ( delExpr ) visit_children = false;
+			}
+		};
+	}
+
+	DeletedExpr * findDeletedExpr( Expression * expr ) {
+		PassVisitor<DeleteFinder> finder;
+		expr->accept( finder );
+		return finder.pass.delExpr;
 	}
 
@@ -130,8 +144,103 @@
 	} // namespace
 
+	namespace {
+		void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {
+			assertf( untyped, "expected a non-null expression." );
+			TypeEnvironment env;
+			AlternativeFinder finder( indexer, env );
+			finder.find( untyped, adjust, prune, failFast );
+
+			#if 0
+			if ( finder.get_alternatives().size() != 1 ) {
+				std::cerr << "untyped expr is ";
+				untyped->print( std::cerr );
+				std::cerr << std::endl << "alternatives are:";
+				for ( const Alternative & alt : finder.get_alternatives() ) {
+					alt.print( std::cerr );
+				} // for
+			} // if
+			#endif
+
+			AltList candidates;
+			for ( Alternative & alt : finder.get_alternatives() ) {
+				if ( pred( alt ) ) {
+					candidates.push_back( std::move( alt ) );
+				}
+			}
+
+			// xxx - if > 1 alternative with same cost, ignore deleted and pick from remaining
+			// choose the lowest cost expression among the candidates
+			AltList winners;
+			findMinCost( candidates.begin(), candidates.end(), back_inserter( winners ) );
+			if ( winners.size() == 0 ) {
+				throw SemanticError( toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: "), untyped );
+			} else if ( winners.size() != 1 ) {
+				std::ostringstream stream;
+				stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
+				untyped->print( stream );
+				stream << "Alternatives are:\n";
+				printAlts( winners, stream, 1 );
+				throw SemanticError( stream.str() );
+			}
+
+			// there is one unambiguous interpretation - move the expression into the with statement
+			Alternative & choice = winners.front();
+			if ( findDeletedExpr( choice.expr ) ) {
+				throw SemanticError( "Unique best alternative includes deleted identifier in ", choice.expr );
+			}
+			alt = std::move( choice );
+		}
+
+		/// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
+		void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {
+			if ( ! untyped ) return;
+			Alternative choice;
+			findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, adjust, prune, failFast );
+			finishExpr( choice.expr, choice.env, untyped->env );
+			delete untyped;
+			untyped = choice.expr;
+			choice.expr = nullptr;
+		}
+
+		bool standardAlternativeFilter( const Alternative & ) {
+			// currently don't need to filter, under normal circumstances.
+			// in the future, this may be useful for removing deleted expressions
+			return true;
+		}
+	} // namespace
+
+	// used in resolveTypeof
+	Expression * resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer ) {
+		TypeEnvironment env;
+		return resolveInVoidContext( expr, indexer, env );
+	}
+
+	Expression * resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
+		// it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
+		// interpretations, an exception has already been thrown.
+		assertf( expr, "expected a non-null expression." );
+
+		static CastExpr untyped( nullptr ); // cast to void
+
+		// set up and resolve expression cast to void
+		untyped.arg = expr;
+		Alternative choice;
+		findUnfinishedKindExpression( &untyped, choice, indexer, "", standardAlternativeFilter, true );
+		CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
+		env = std::move( choice.env );
+
+		// clean up resolved expression
+		Expression * ret = castExpr->arg;
+		castExpr->arg = nullptr;
+
+		// unlink the arg so that it isn't deleted twice at the end of the program
+		untyped.arg = nullptr;
+		return ret;
+	}
+
 	void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {
 		resetTyVarRenaming();
 		TypeEnvironment env;
-		Expression *newExpr = resolveInVoidContext( untyped, indexer, env );
+		Expression * newExpr = resolveInVoidContext( untyped, indexer, env );
 		finishExpr( newExpr, env, untyped->env );
 		delete untyped;
@@ -140,24 +249,5 @@
 
 	void findSingleExpression( Expression *&untyped, const SymTab::Indexer &indexer ) {
-		if ( ! untyped ) return;
-		TypeEnvironment env;
-		AlternativeFinder finder( indexer, env );
-		finder.find( untyped );
-		#if 0
-		if ( finder.get_alternatives().size() != 1 ) {
-			std::cerr << "untyped expr is ";
-			untyped->print( std::cerr );
-			std::cerr << std::endl << "alternatives are:";
-			for ( const Alternative & alt : finder.get_alternatives() ) {
-				alt.print( std::cerr );
-			} // for
-		} // if
-		#endif
-		assertf( finder.get_alternatives().size() == 1, "findSingleExpression: must have exactly one alternative at the end: (%zd) %s", finder.get_alternatives().size(), toString( untyped ).c_str() );
-		Alternative &choice = finder.get_alternatives().front();
-		Expression *newExpr = choice.expr->clone();
-		finishExpr( newExpr, choice.env, untyped->env );
-		delete untyped;
-		untyped = newExpr;
+		findKindExpression( untyped, indexer, "", standardAlternativeFilter );
 	}
 
@@ -170,41 +260,6 @@
 
 	namespace {
-		/// resolve `untyped` to the expression whose type satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
-		template<typename Pred>
-		void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, Pred pred) {
-			TypeEnvironment env;
-			AlternativeFinder finder( indexer, env );
-			finder.findWithAdjustment( untyped );
-
-			AltList candidates;
-			for ( Alternative & alt : finder.get_alternatives() ) {
-				if ( pred( alt.expr->result ) ) {
-					candidates.push_back( std::move( alt ) );
-				}
-			}
-
-			// choose the lowest cost expression among the candidates
-			AltList winners;
-			findMinCost( candidates.begin(), candidates.end(), back_inserter( winners ) );
-			if ( winners.size() == 0 ) {
-				throw SemanticError( "No reasonable alternatives for " + kindStr + " expression: ", untyped );
-			} else if ( winners.size() != 1 ) {
-				std::ostringstream stream;
-				stream << "Cannot choose between " << winners.size() << " alternatives for " + kindStr +  " expression\n";
-				untyped->print( stream );
-				stream << "Alternatives are:\n";
-				printAlts( winners, stream, 1 );
-				throw SemanticError( stream.str() );
-			}
-
-			// there is one unambiguous interpretation - move the expression into the with statement
-			Alternative & alt = winners.front();
-			finishExpr( alt.expr, alt.env, untyped->env );
-			delete untyped;
-			untyped = alt.expr;
-			alt.expr = nullptr;
-		}
-
-		bool isIntegralType( Type *type ) {
+		bool isIntegralType( const Alternative & alt ) {
+			Type * type = alt.expr->result;
 			if ( dynamic_cast< EnumInstType * >( type ) ) {
 				return true;
@@ -559,5 +614,5 @@
 			if( func_candidates.size() > 1 ) { SemanticError top( "Ambiguous function in call to waitfor"            ); top.append( errors ); throw top; }
 			if( args_candidates.size() > 1 ) { SemanticError top( "Ambiguous arguments in call to waitfor"           ); top.append( errors ); throw top; }
-
+			// TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
 
 			// Swap the results from the alternative with the unresolved values.
@@ -592,6 +647,6 @@
 	}
 
-	bool isStructOrUnion( Type * t ) {
-		t = t->stripReferences();
+	bool isStructOrUnion( const Alternative & alt ) {
+		Type * t = alt.expr->result->stripReferences();
 		return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );
 	}
