Index: src/Common/PersistentMap.h
===================================================================
--- src/Common/PersistentMap.h	(revision fdae91367ec3ec0ae0d11f084e14da4fd527b06c)
+++ src/Common/PersistentMap.h	(revision 42f1279c182e0cf2f329749d809a250ef38193f3)
@@ -122,6 +122,9 @@
 
 public:
-	using size_type = std::size_t;
-
+	using key_type = typename Base::key_type;
+	using mapped_type = typename Base::mapped_type;
+	using value_type = typename Base::value_type;
+	using size_type = typename Base::size_type;
+	using difference_type = typename Base::difference_type;
 	using iterator = typename Base::const_iterator;
 
Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision fdae91367ec3ec0ae0d11f084e14da4fd527b06c)
+++ src/SymTab/Indexer.cc	(revision 42f1279c182e0cf2f329749d809a250ef38193f3)
@@ -22,4 +22,5 @@
 #include <unordered_set>           // for unordered_set
 #include <utility>                 // for pair, make_pair, move
+#include <vector>                  // for vector
 
 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
@@ -386,11 +387,147 @@
 	}
 
+	/// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
+	std::string getOtypeKey( FunctionDecl* function ) {
+		auto& params = function->type->parameters;
+		assert( ! params.empty() );
+		// use base type of pointer, so that qualifiers on the pointer type aren't considered.
+		Type* base = InitTweak::getPointerBase( params.front()->get_type() );
+		assert( base );
+		return Mangler::mangle( base );
+	}
+
+	/// gets the declaration for the function acting on a type specified by otype key, 
+	/// nullptr if none such
+	FunctionDecl * getFunctionForOtype( DeclarationWithType * decl, const std::string& otypeKey ) {
+		FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl );
+		if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
+		return func;
+	}
+
+	bool Indexer::removeSpecialOverrides( 
+			Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) {
+		// if a type contains user defined ctor/dtor/assign, then special rules trigger, which 
+		// determinethe set of ctor/dtor/assign that can be used  by the requester. In particular, 
+		// if the user defines a default ctor, then the generated default ctor is unavailable, 
+		// likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated 
+		// field ctors are available. If the user defines any ctor then the generated default ctor 
+		// is unavailable (intrinsic default ctor must be overridden exactly). If the user defines 
+		// anything that looks like a copy constructor, then the generated copy constructor is 
+		// unavailable, and likewise for the assignment operator.
+
+		// only relevant on function declarations
+		FunctionDecl * function = dynamic_cast< FunctionDecl * >( data.id );
+		if ( ! function ) return true;
+		// only need to perform this check for constructors, destructors, and assignment functions
+		if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true;
+
+		// set up information for this type
+		bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
+		bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name );
+		std::string dataOtypeKey = getOtypeKey( function );
+
+		if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
+			// this is a user-defined copy function
+			// if this is the first such, delete/remove non-user-defined overloads as needed
+			std::vector< std::string > removed;
+			std::vector< MangleTable::value_type > deleted;
+			bool alreadyUserDefinedFunc = false;
+			
+			for ( const auto& entry : *mangleTable ) {
+				// skip decls that aren't functions or are for the wrong type
+				FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
+				if ( ! decl ) continue;
+
+				bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name );
+				if ( ! LinkageSpec::isOverridable( decl->linkage ) ) {
+					// matching user-defined function
+					if ( isCopyFunc ) {
+						// mutation already performed, return early
+						return true;
+					} else {
+						// note that non-copy deletions already performed
+						alreadyUserDefinedFunc = true;
+					}
+				} else {
+					// non-user-defined function; mark for deletion/removal as appropriate
+					if ( isCopyFunc ) {
+						removed.push_back( entry.first );
+					} else if ( ! alreadyUserDefinedFunc ) {
+						deleted.push_back( entry );
+					}
+				}
+			}
+
+			// perform removals from mangle table, and deletions if necessary
+			for ( const auto& key : removed ) {
+				mangleTable = mangleTable->erase( key );
+			}
+			if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) {
+				mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
+			}
+		} else if ( dataIsUserDefinedFunc ) {
+			// this is a user-defined non-copy function
+			// if this is the first user-defined function, delete non-user-defined overloads
+			std::vector< MangleTable::value_type > deleted;
+			
+			for ( const auto& entry : *mangleTable ) {
+				// skip decls that aren't functions or are for the wrong type
+				FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
+				if ( ! decl ) continue;
+
+				// exit early if already a matching user-defined function;
+				// earlier function will have mutated table
+				if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true;
+
+				// skip mutating intrinsic functions
+				if ( decl->linkage == LinkageSpec::Intrinsic ) continue;
+
+				// user-defined non-copy functions do not override copy functions
+				if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue;
+
+				// this function to be deleted after mangleTable iteration is complete
+				deleted.push_back( entry );
+			}
+
+			// mark deletions to update mangle table
+			// this needs to be a separate loop because of iterator invalidation
+			for ( const auto& entry : deleted ) {
+				mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
+			}
+		} else if ( function->linkage != LinkageSpec::Intrinsic ) {
+			// this is an overridable generated function
+			// if there already exists a matching user-defined function, delete this appropriately
+			for ( const auto& entry : *mangleTable ) {
+				// skip decls that aren't functions or are for the wrong type
+				FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
+				if ( ! decl ) continue;
+
+				// skip non-user-defined functions
+				if ( LinkageSpec::isOverridable( decl->linkage ) ) continue;
+
+				if ( dataIsCopyFunc ) {
+					// remove current function if exists a user-defined copy function
+					// since the signatures for copy functions don't need to match exactly, using 
+					// a delete statement is the wrong approach
+					if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false;
+				} else {
+					// mark current function deleted by first user-defined function found
+					data.deleteStmt = decl;
+					return true;
+				}
+			}
+		}
+		
+		// nothing (more) to fix, return true
+		return true;
+	}
+
 	void Indexer::addId( 
 			DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr, 
 			BaseSyntaxNode * deleteStmt ) {
 		++*stats().add_calls;
-		if ( decl->name == "" ) return;
+		const std::string &name = decl->name;
+		if ( name == "" ) return;
 		
-		const std::string &name = decl->name;
 		std::string mangleName;
 		if ( LinkageSpec::isOverridable( decl->linkage ) ) {
@@ -454,8 +591,8 @@
 		// add/overwrite with new identifier
 		lazyInitScope();
+		IdData data{ decl, baseExpr, deleteStmt, scope };
+		if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
 		*stats().map_mutations += 2;
-		idTable = idTable->set( 
-			name,
-			mangleTable->set( mangleName, IdData{ decl, baseExpr, deleteStmt, scope } ) );
+		idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
 	}
 
Index: src/SymTab/Indexer.h
===================================================================
--- src/SymTab/Indexer.h	(revision fdae91367ec3ec0ae0d11f084e14da4fd527b06c)
+++ src/SymTab/Indexer.h	(revision 42f1279c182e0cf2f329749d809a250ef38193f3)
@@ -144,6 +144,9 @@
 		/// Removes matching autogenerated constructors and destructors
 		/// so that they will not be selected
-		/// void removeSpecialOverrides( FunctionDecl *decl );
 		void removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const;
+
+		/// Removes matching autogenerated constructors and destructors so that they will not be 
+		/// selected. If returns false, passed decl should not be added.
+		bool removeSpecialOverrides( IdData& decl, MangleTable::Ptr& mangleTable );
 
 		/// Options for handling identifier conflicts
