Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision 490ff5c3cdf33976fd18d953a739387a1031d3c6)
+++ src/SymTab/Indexer.cc	(revision 0ac366bb815a57d58e603b8e1ef744766f2255e4)
@@ -286,7 +286,7 @@
 	}
 
-	DeclarationWithType *Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
-		if ( ! tables ) return 0;
-		if ( tables->scope < scope ) return 0;
+	const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
+		if ( ! tables ) return nullptr;
+		if ( tables->scope < scope ) return nullptr;
 
 		IdTable::const_iterator decls = tables->idTable.find( id );
@@ -294,8 +294,12 @@
 			const MangleTable &mangleTable = decls->second;
 			MangleTable::const_iterator decl = mangleTable.find( mangleName );
-			if ( decl != mangleTable.end() ) return decl->second.id;
+			if ( decl != mangleTable.end() ) return &decl->second;
 		}
 
 		return tables->base.lookupIdAtScope( id, mangleName, scope );
+	}
+
+	Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) {
+		return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
 	}
 
@@ -373,20 +377,28 @@
 	}
 
-	bool addedIdConflicts( DeclarationWithType *existing, DeclarationWithType *added ) {
+	bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
 		// if we're giving the same name mangling to things of different types then there is something wrong
-		assert( (dynamic_cast<ObjectDecl*>( added ) && dynamic_cast<ObjectDecl*>( existing ) )
-			|| (dynamic_cast<FunctionDecl*>( added ) && dynamic_cast<FunctionDecl*>( existing ) ) );
-
-		if ( LinkageSpec::isOverridable( existing->get_linkage() ) ) {
+		assert( (dynamic_cast<ObjectDecl*>( added ) && dynamic_cast<ObjectDecl*>( existing.id ) )
+			|| (dynamic_cast<FunctionDecl*>( added ) && dynamic_cast<FunctionDecl*>( existing.id ) ) );
+
+		if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
 			// new definition shadows the autogenerated one, even at the same scope
 			return false;
-		} else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing->get_type(), Indexer() ) ) {
+		} else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
+
+			// it is a conflict if one declaration is deleted and the other is not
+			if ( deleteStmt && ! existing.deleteStmt ) {
+				return handleConflicts( existing, "deletion of defined identifier " );
+			} else if ( ! deleteStmt && existing.deleteStmt ) {
+				return handleConflicts( existing, "definition of deleted identifier " );
+			}
+
 			// typesCompatible doesn't really do the right thing here. When checking compatibility of function types,
 			// we should ignore outermost pointer qualifiers, except _Atomic?
-			FunctionDecl *newentry = dynamic_cast< FunctionDecl* >( added );
-			FunctionDecl *oldentry = dynamic_cast< FunctionDecl* >( existing );
+			FunctionDecl * newentry = dynamic_cast< FunctionDecl * >( added );
+			FunctionDecl * oldentry = dynamic_cast< FunctionDecl * >( existing.id );
 			if ( newentry && oldentry ) {
 				if ( newentry->get_statements() && oldentry->get_statements() ) {
-					throw SemanticError( "duplicate function definition for ", added );
+					return handleConflicts( existing, "duplicate function definition for " );
 				} // if
 			} else {
@@ -395,12 +407,12 @@
 				// xxx - perhaps it's actually if either is intrinsic then this is okay?
 				//       might also need to be same storage class?
-				ObjectDecl *newobj = dynamic_cast< ObjectDecl* >( added );
-				ObjectDecl *oldobj = dynamic_cast< ObjectDecl* >( existing );
+				ObjectDecl * newobj = dynamic_cast< ObjectDecl * >( added );
+				ObjectDecl * oldobj = dynamic_cast< ObjectDecl * >( existing.id );
 				if ( ! newobj->get_storageClasses().is_extern && ! oldobj->get_storageClasses().is_extern ) {
-					throw SemanticError( "duplicate object definition for ", added );
+					return handleConflicts( existing, "duplicate object definition for " );
 				} // if
 			} // if
 		} else {
-			throw SemanticError( "duplicate definition for ", added );
+			return handleConflicts( existing, "duplicate definition for " );
 		} // if
 
@@ -408,5 +420,5 @@
 	}
 
-	void Indexer::addId( DeclarationWithType *decl, Expression * baseExpr ) {
+	void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) {
 		if ( decl->name == "" ) return;
 		debugPrint( "Adding Id " << decl->name << std::endl );
@@ -441,10 +453,20 @@
 
 		// Skip repeat declarations of the same identifier
-		DeclarationWithType *existing = lookupIdAtScope( name, mangleName, scope );
-		if ( existing && addedIdConflicts( existing, decl ) ) return;
+		IdData * existing = lookupIdAtScope( name, mangleName, scope );
+		if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return;
 
 		// add to indexer
-		tables->idTable[ name ][ mangleName ] = { decl, baseExpr };
+		tables->idTable[ name ][ mangleName ] = { decl, baseExpr, deleteStmt };
 		++tables->size;
+	}
+
+	void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
+		// default handling of conflicts is to raise an error
+		addId( decl, [decl](IdData &, const std::string & msg) { throw SemanticError( msg, decl ); return true; }, baseExpr );
+	}
+
+	void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
+		// default handling of conflicts is to raise an error
+		addId( decl, [decl](IdData &, const std::string & msg) { throw SemanticError( msg, decl ); return true; }, nullptr, deleteStmt );
 	}
 
@@ -573,8 +595,8 @@
 	}
 
-	void Indexer::addMembers( AggregateDecl * aggr, Expression * expr ) {
+	void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) {
 		for ( Declaration * decl : aggr->members ) {
 			if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
-				addId( dwt, expr );
+				addId( dwt, handleConflicts, expr );
 				if ( dwt->name == "" ) {
 					Type * t = dwt->get_type()->stripReferences();
@@ -582,5 +604,5 @@
 						Expression * base = expr->clone();
 						ResolvExpr::referenceToRvalueConversion( base );
-						addMembers( t->getAggr(), new MemberExpr( dwt, base ) );
+						addMembers( t->getAggr(), new MemberExpr( dwt, base ), handleConflicts );
 					}
 				}
@@ -589,5 +611,5 @@
 	}
 
-	void Indexer::addWith( std::list< Expression * > & withExprs ) {
+	void Indexer::addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ) {
 		for ( Expression * expr : withExprs ) {
 			if ( expr->result ) {
@@ -595,5 +617,9 @@
 				assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
 
-				addMembers( aggr, expr );
+				addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
+					// on conflict, delete the identifier
+					existing.deleteStmt = withStmt;
+					return true;
+				});
 			}
 		}
@@ -680,16 +706,18 @@
 
 	Expression * Indexer::IdData::combine() const {
+		Expression * ret = nullptr;
 		if ( baseExpr ) {
 			Expression * base = baseExpr->clone();
 			ResolvExpr::referenceToRvalueConversion( base );
-			Expression * ret = new MemberExpr( id, base );
+			ret = new MemberExpr( id, base );
 			// xxx - this introduces hidden environments, for now remove them.
 			// std::swap( base->env, ret->env );
 			delete base->env;
 			base->env = nullptr;
-			return ret;
-		} else {
-			return new VariableExpr( id );
-		}
+		} else {
+			ret = new VariableExpr( id );
+		}
+		if ( deleteStmt ) ret = new DeletedExpr( ret, deleteStmt );
+		return ret;
 	}
 } // namespace SymTab
Index: src/SymTab/Indexer.h
===================================================================
--- src/SymTab/Indexer.h	(revision 490ff5c3cdf33976fd18d953a739387a1031d3c6)
+++ src/SymTab/Indexer.h	(revision 0ac366bb815a57d58e603b8e1ef744766f2255e4)
@@ -19,4 +19,5 @@
 #include <list>               // for list
 #include <string>             // for string
+#include <functional>         // for function
 
 #include "SynTree/Visitor.h"  // for Visitor
@@ -65,5 +66,6 @@
 
 		/// looks up a specific mangled ID at the given scope
-		DeclarationWithType *lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
+		IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope );
+		const IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
 		/// returns true if there exists a declaration with C linkage and the given name with a different mangled name
 		bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
@@ -77,5 +79,9 @@
 		TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const;
 
-		void addId( DeclarationWithType *decl, Expression * baseExpr = nullptr );
+		typedef std::function<bool(IdData &, const std::string &)> ConflictFunction;
+
+		void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr );
+		void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt );
+
 		void addType( NamedTypeDecl *decl );
 		void addStruct( const std::string &id );
@@ -87,8 +93,8 @@
 
 		/// adds all of the IDs from WithStmt exprs
-		void addWith( std::list< Expression * > & withExprs );
+		void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt );
 
 		/// adds all of the members of the Aggregate (addWith helper)
-		void addMembers( AggregateDecl * aggr, Expression * expr );
+		void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction );
 
 		/// convenience function for adding a list of Ids to the indexer
@@ -120,4 +126,7 @@
 		/// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope)
 		void makeWritable();
+
+		/// common code for addId, addDeletedId, etc.
+		void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
 	};
 } // namespace SymTab
