Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 3ca540ff8fca8be28ec085a72a11b96bf920dd76)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision a40d5034e9a41778a6d525a1b015a29b2bed0527)
@@ -469,11 +469,12 @@
 			std::cerr << std::endl;
 		)
-		std::list< DeclarationWithType* > candidates;
+		std::list< SymTab::Indexer::IdData > candidates;
 		decls.lookupId( curDecl->get_name(), candidates );
 ///   if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
-		for ( std::list< DeclarationWithType* >::const_iterator candidate = candidates.begin(); candidate != candidates.end(); ++candidate ) {
+		for ( const auto & data : candidates ) {
+			DeclarationWithType * candidate = data.id;
 			PRINT(
 				std::cerr << "inferRecursive: candidate is ";
-				(*candidate)->print( std::cerr );
+				candidate->print( std::cerr );
 				std::cerr << std::endl;
 			)
@@ -482,5 +483,5 @@
 			TypeEnvironment newEnv( newAlt.env );
 			OpenVarSet newOpenVars( openVars );
-			Type *adjType = (*candidate)->get_type()->clone();
+			Type *adjType = candidate->get_type()->clone();
 			adjustExprType( adjType, newEnv, indexer );
 			adjType->accept( global_renamer );
@@ -500,6 +501,5 @@
 				Alternative newerAlt( newAlt );
 				newerAlt.env = newEnv;
-				assertf( (*candidate)->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( *candidate ).c_str() );
-				DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) );
+				assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
 
 				// everything with an empty idChain was pulled in by the current assertion.
@@ -516,5 +516,5 @@
 				// DOESN'T WORK: grandchild nodes conflict with their cousins
 				//if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue;
-				Expression *varExpr = new VariableExpr( candDecl );
+				Expression *varExpr = data.combine();
 				delete varExpr->get_result();
 				varExpr->set_result( adjType->clone() );
@@ -522,6 +522,6 @@
 					std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
 					curDecl->print( std::cerr );
-					std::cerr << " with declaration " << (*candidate)->get_uniqueId() << " ";
-					(*candidate)->print( std::cerr );
+					std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
+					candidate->print( std::cerr );
 					std::cerr << std::endl;
 				)
@@ -532,5 +532,5 @@
 				}
 				// XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
-				(*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
+				(*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
 				inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out );
 			} else {
@@ -1317,16 +1317,17 @@
 
 	void AlternativeFinder::visit( NameExpr *nameExpr ) {
-		std::list< DeclarationWithType* > declList;
+		std::list< SymTab::Indexer::IdData > declList;
 		indexer.lookupId( nameExpr->get_name(), declList );
 		PRINT( std::cerr << "nameExpr is " << nameExpr->get_name() << std::endl; )
-		for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) {
-			VariableExpr newExpr( *i );
-			alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
+		for ( auto & data : declList ) {
+			Expression * newExpr = data.combine();
+			// xxx - add in extra cost for with-statement exprs?
+			alternatives.push_back( Alternative( newExpr, env, Cost::zero ) );
 			PRINT(
 				std::cerr << "decl is ";
-				(*i)->print( std::cerr );
+				data.id->print( std::cerr );
 				std::cerr << std::endl;
 				std::cerr << "newExpr is ";
-				newExpr.print( std::cerr );
+				newExpr->print( std::cerr );
 				std::cerr << std::endl;
 			)
@@ -1420,21 +1421,25 @@
 	}
 
-	void AlternativeFinder::resolveAttr( DeclarationWithType *funcDecl, FunctionType *function, Type *argType, const TypeEnvironment &env ) {
-		// assume no polymorphism
-		// assume no implicit conversions
-		assert( function->get_parameters().size() == 1 );
-		PRINT(
-			std::cerr << "resolvAttr: funcDecl is ";
-			funcDecl->print( std::cerr );
-			std::cerr << " argType is ";
-			argType->print( std::cerr );
-			std::cerr << std::endl;
-		)
-		if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
-			alternatives.push_back( Alternative( new AttrExpr( new VariableExpr( funcDecl ), argType->clone() ), env, Cost::zero ) );
-			for ( std::list< DeclarationWithType* >::iterator i = function->get_returnVals().begin(); i != function->get_returnVals().end(); ++i ) {
-				alternatives.back().expr->set_result( (*i)->get_type()->clone() );
-			} // for
-		} // if
+	namespace {
+		void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
+			// assume no polymorphism
+			// assume no implicit conversions
+			assert( function->get_parameters().size() == 1 );
+			PRINT(
+				std::cerr << "resolvAttr: funcDecl is ";
+				data.id->print( std::cerr );
+				std::cerr << " argType is ";
+				argType->print( std::cerr );
+				std::cerr << std::endl;
+			)
+			const SymTab::Indexer & indexer = finder.get_indexer();
+			AltList & alternatives = finder.get_alternatives();
+			if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
+				alternatives.push_back( Alternative( new AttrExpr( data.combine(), argType->clone() ), env, Cost::zero ) );
+				for ( DeclarationWithType * retVal : function->returnVals ) {
+					alternatives.back().expr->result = retVal->get_type()->clone();
+				} // for
+			} // if
+		}
 	}
 
@@ -1443,14 +1448,15 @@
 		NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
 		assert( nameExpr );
-		std::list< DeclarationWithType* > attrList;
+		std::list< SymTab::Indexer::IdData > attrList;
 		indexer.lookupId( nameExpr->get_name(), attrList );
 		if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
-			for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
+			for ( auto & data : attrList ) {
+				DeclarationWithType * id = data.id;
 				// check if the type is function
-				if ( FunctionType *function = dynamic_cast< FunctionType* >( (*i)->get_type() ) ) {
+				if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
 					// assume exactly one parameter
 					if ( function->get_parameters().size() == 1 ) {
 						if ( attrExpr->get_isType() ) {
-							resolveAttr( *i, function, attrExpr->get_type(), env );
+							resolveAttr( data, function, attrExpr->get_type(), env, *this );
 						} else {
 							AlternativeFinder finder( indexer, env );
@@ -1458,5 +1464,5 @@
 							for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
 								if ( choice->expr->get_result()->size() == 1 ) {
-									resolveAttr(*i, function, choice->expr->get_result(), choice->env );
+									resolveAttr(data, function, choice->expr->get_result(), choice->env, *this );
 								} // fi
 							} // for
@@ -1466,7 +1472,6 @@
 			} // for
 		} else {
-			for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
-				VariableExpr newExpr( *i );
-				alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
+			for ( auto & data : attrList ) {
+				alternatives.push_back( Alternative( data.combine(), env, Cost::zero ) );
 				renameTypes( alternatives.back().expr );
 			} // for
Index: src/ResolvExpr/AlternativeFinder.h
===================================================================
--- src/ResolvExpr/AlternativeFinder.h	(revision 3ca540ff8fca8be28ec085a72a11b96bf920dd76)
+++ src/ResolvExpr/AlternativeFinder.h	(revision a40d5034e9a41778a6d525a1b015a29b2bed0527)
@@ -142,5 +142,4 @@
 		template< typename OutputIterator >
 		void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
-		void resolveAttr( DeclarationWithType *funcDecl, FunctionType *function, Type *argType, const TypeEnvironment &env );
 
 		const SymTab::Indexer &indexer;
Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision 3ca540ff8fca8be28ec085a72a11b96bf920dd76)
+++ src/SymTab/Indexer.cc	(revision a40d5034e9a41778a6d525a1b015a29b2bed0527)
@@ -40,5 +40,9 @@
 
 namespace SymTab {
-	typedef std::unordered_map< std::string, DeclarationWithType* > MangleTable;
+	std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) {
+		return out << "(" << data.id << "," << data.baseExpr << ")";
+	}
+
+	typedef std::unordered_map< std::string, Indexer::IdData > MangleTable;
 	typedef std::unordered_map< std::string, MangleTable > IdTable;
 	typedef std::unordered_map< std::string, NamedTypeDecl* > TypeTable;
@@ -97,5 +101,5 @@
 	}
 
-	void Indexer::removeSpecialOverrides( const std::string &id, std::list< DeclarationWithType * > & out ) const {
+	void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const {
 		// only need to perform this step for constructors, destructors, and assignment functions
 		if ( ! CodeGen::isCtorDtorAssign( id ) ) return;
@@ -104,5 +108,5 @@
 		struct ValueType {
 			struct DeclBall {
-				FunctionDecl * decl;
+				IdData decl;
 				bool isUserDefinedFunc; // properties for this particular decl
 				bool isDefaultCtor;
@@ -120,10 +124,11 @@
 			// another FunctionDecl for the current type was found - determine
 			// if it has special properties and update data structure accordingly
-			ValueType & operator+=( FunctionDecl * function ) {
+			ValueType & operator+=( IdData data ) {
+				DeclarationWithType * function = data.id;
 				bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->get_linkage() );
 				bool isDefaultCtor = InitTweak::isDefaultConstructor( function );
 				bool isDtor = InitTweak::isDestructor( function );
 				bool isCopyFunc = InitTweak::isCopyFunction( function, function->get_name() );
-				decls.push_back( DeclBall{ function, isUserDefinedFunc, isDefaultCtor, isDtor, isCopyFunc } );
+				decls.push_back( DeclBall{ data, isUserDefinedFunc, isDefaultCtor, isDtor, isCopyFunc } );
 				existsUserDefinedFunc = existsUserDefinedFunc || isUserDefinedFunc;
 				existsUserDefinedCtor = existsUserDefinedCtor || (isUserDefinedFunc && CodeGen::isConstructor( function->get_name() ) );
@@ -135,11 +140,11 @@
 		}; // ValueType
 
-		std::list< DeclarationWithType * > copy;
+		std::list< IdData > copy;
 		copy.splice( copy.end(), out );
 
 		// organize discovered declarations by type
 		std::unordered_map< std::string, ValueType > funcMap;
-		for ( DeclarationWithType * decl : copy ) {
-			if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl ) ) {
+		for ( auto decl : copy ) {
+			if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) {
 				std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
 				assert( ! params.empty() );
@@ -147,5 +152,5 @@
 				Type * base = InitTweak::getPointerBase( params.front()->get_type() );
 				assert( base );
-				funcMap[ Mangler::mangle( base ) ] += function;
+				funcMap[ Mangler::mangle( base ) ] += decl;
 			} else {
 				out.push_back( decl );
@@ -164,5 +169,5 @@
 				bool noUserDefinedFunc = ! val.existsUserDefinedFunc;
 				bool isUserDefinedFunc = ball.isUserDefinedFunc;
-				bool isAcceptableDefaultCtor = (! val.existsUserDefinedCtor || (! val.existsUserDefinedDefaultCtor && ball.decl->get_linkage() == LinkageSpec::Intrinsic)) && ball.isDefaultCtor; // allow default constructors only when no user-defined constructors exist, except in the case of intrinsics, which require exact overrides
+				bool isAcceptableDefaultCtor = (! val.existsUserDefinedCtor || (! val.existsUserDefinedDefaultCtor && ball.decl.id->get_linkage() == LinkageSpec::Intrinsic)) && ball.isDefaultCtor; // allow default constructors only when no user-defined constructors exist, except in the case of intrinsics, which require exact overrides
 				bool isAcceptableCopyFunc = ! val.existsUserDefinedCopyFunc && ball.isCopyFunc; // handles copy ctor and assignment operator
 				bool isAcceptableDtor = ! val.existsUserDefinedDtor && ball.isDtor;
@@ -219,5 +224,5 @@
 	}
 
-	void Indexer::lookupId( const std::string &id, std::list< DeclarationWithType* > &out ) const {
+	void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
 		std::unordered_set< std::string > foundMangleNames;
 
@@ -289,5 +294,5 @@
 			const MangleTable &mangleTable = decls->second;
 			MangleTable::const_iterator decl = mangleTable.find( mangleName );
-			if ( decl != mangleTable.end() ) return decl->second;
+			if ( decl != mangleTable.end() ) return decl->second.id;
 		}
 
@@ -304,5 +309,5 @@
 			for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
 				// check for C decls with the same name, skipping those with a compatible type (by mangleName)
-				if ( ! LinkageSpec::isMangled( decl->second->get_linkage() ) && decl->first != mangleName ) return true;
+				if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true;
 			}
 		}
@@ -321,5 +326,5 @@
 				// check for C decls with the same name, skipping
 				// those with an incompatible type (by mangleName)
-				if ( ! LinkageSpec::isMangled( decl->second->get_linkage() ) && decl->first == mangleName ) return true;
+				if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true;
 			}
 		}
@@ -403,5 +408,5 @@
 	}
 
-	void Indexer::addId( DeclarationWithType *decl ) {
+	void Indexer::addId( DeclarationWithType *decl, Expression * baseExpr ) {
 		debugPrint( "Adding Id " << decl->name << std::endl );
 		makeWritable();
@@ -439,5 +444,5 @@
 
 		// add to indexer
-		tables->idTable[ name ][ mangleName ] = decl;
+		tables->idTable[ name ][ mangleName ] = { decl, baseExpr };
 		++tables->size;
 	}
@@ -573,8 +578,7 @@
 				assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
 
-				// xxx - this is wrong, needs to somehow hook up chain of objects
 				for ( Declaration * decl : aggr->members ) {
 					if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
-						addId( dwt );
+						addId( dwt, expr );
 					}
 				}
@@ -661,4 +665,18 @@
 
 	}
+
+	Expression * Indexer::IdData::combine() const {
+		if ( baseExpr ) {
+			Expression * base = baseExpr->clone();
+			Expression * 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 );
+		}
+	}
 } // namespace SymTab
 
Index: src/SymTab/Indexer.h
===================================================================
--- src/SymTab/Indexer.h	(revision 3ca540ff8fca8be28ec085a72a11b96bf920dd76)
+++ src/SymTab/Indexer.h	(revision a40d5034e9a41778a6d525a1b015a29b2bed0527)
@@ -39,6 +39,13 @@
 		void leaveScope();
 
+		struct IdData {
+			DeclarationWithType * id;
+			Expression * baseExpr; // WithExpr
+
+			Expression * combine() const;
+		};
+
 		/// Gets all declarations with the given ID
-		void lookupId( const std::string &id, std::list< DeclarationWithType* > &out ) const;
+		void lookupId( const std::string &id, std::list< IdData > &out ) const;
 		/// Gets the top-most type declaration with the given ID
 		NamedTypeDecl *lookupType( const std::string &id ) const;
@@ -67,5 +74,5 @@
 		TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const;
 
-		void addId( DeclarationWithType *decl );
+		void addId( DeclarationWithType *decl, Expression * baseExpr = nullptr );
 		void addType( NamedTypeDecl *decl );
 		void addStruct( const std::string &id );
@@ -103,5 +110,5 @@
 		// so that they will not be selected
 		// void removeSpecialOverrides( FunctionDecl *decl );
-		void removeSpecialOverrides( const std::string &id, std::list< DeclarationWithType * > & out ) const;
+		void removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const;
 
 		/// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope)
