Index: src/AST/DeclReplacer.cpp
===================================================================
--- src/AST/DeclReplacer.cpp	(revision b0abc8a02c452bd4a4675437c5aa0ca43e19893c)
+++ src/AST/DeclReplacer.cpp	(revision e9b444897a7f44c690ecbcd5c3178b3cfd90c195)
@@ -14,5 +14,82 @@
 //
 
-#warning unimplemented
+#include "DeclReplacer.hpp"
+#include "Expr.hpp"
+#include "Type.hpp"
+
+#include "Pass.hpp"
+
+namespace ast {
+
+namespace DeclReplacer {
+	namespace {
+		struct DeclReplacer {
+		private:
+			const DeclMap & declMap;
+			const TypeMap & typeMap;
+			bool debug;
+
+		public:
+			DeclReplacer(const DeclMap & declMap, const TypeMap & typeMap, bool debug)
+				: declMap( declMap ), typeMap( typeMap ), debug( debug )
+			{}
+
+			const ast::VariableExpr * previsit( const ast::VariableExpr * );
+			const ast::TypeInstType * previsit( const ast::TypeInstType * );
+		};
+	}
+
+	const ast::Node * replace( const ast::Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug ) {
+		if(!node) return nullptr;
+		Pass<DeclReplacer> replacer = { declMap, typeMap, debug };
+		return node->accept( replacer );
+	}
+
+	const ast::Node * replace( const ast::Node * node, const DeclMap & declMap, bool debug ) {
+		TypeMap typeMap;
+		return replace( node, declMap, typeMap, debug );
+	}
+
+	const ast::Node * replace( const ast::Node * node, const TypeMap & typeMap, bool debug ) {
+		DeclMap declMap;
+		return replace( node, declMap, typeMap, debug );
+	}
+
+	namespace {
+		// replace variable with new node from decl map
+		const ast::VariableExpr * DeclReplacer::previsit( const VariableExpr * varExpr ) {
+			// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
+			if ( !declMap.count( varExpr->var ) ) return varExpr;
+
+			auto replacement = declMap.at( varExpr->var );
+			if ( debug ) {
+				std::cerr << "replacing variable reference: "
+					<< (void*)varExpr->var.get() << " " << varExpr->var
+					<< " with " << (void*)replacement << " " << replacement
+					<< std::endl;
+			}
+			auto nexpr = mutate(varExpr);
+			nexpr->var = replacement;
+			return nexpr;
+		}
+
+		const TypeInstType * DeclReplacer::previsit( const TypeInstType * inst ) {
+			if ( !typeMap.count( inst->base ) ) return inst;
+
+			auto replacement = typeMap.at( inst->base );
+			if ( debug ) {
+				std::cerr << "replacing type reference: "
+					<< (void*)inst->base.get() << " " << inst->base
+					<< " with " << (void*)replacement << " " << replacement
+					<< std::endl;
+			}
+			auto ninst = mutate(inst);
+			ninst->base = replacement;
+			return ninst;
+		}
+	}
+}
+
+}
 
 // Local Variables: //
Index: src/AST/DeclReplacer.hpp
===================================================================
--- src/AST/DeclReplacer.hpp	(revision b0abc8a02c452bd4a4675437c5aa0ca43e19893c)
+++ src/AST/DeclReplacer.hpp	(revision e9b444897a7f44c690ecbcd5c3178b3cfd90c195)
@@ -25,10 +25,10 @@
 
 	namespace DeclReplacer {
-		using DeclMap = std::unordered_map< DeclWithType*, DeclWithType* >;
-		using TypeMap = std::unordered_map< TypeDecl*, TypeDecl* >;
+		using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
+		using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
 
-		void replace( Node* node, const DeclMap& declMap );
-		void replace( Node* node, const TypeMap& typeMap );
-		void replace( Node* node, const DeclMap& declMap, const TypeMap& typeMap );
+		const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
+		const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
+		const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
 	}
 }
Index: src/AST/Stmt.cpp
===================================================================
--- src/AST/Stmt.cpp	(revision b0abc8a02c452bd4a4675437c5aa0ca43e19893c)
+++ src/AST/Stmt.cpp	(revision e9b444897a7f44c690ecbcd5c3178b3cfd90c195)
@@ -16,11 +16,41 @@
 #include "Stmt.hpp"
 
+
 #include "DeclReplacer.hpp"
+#include "Type.hpp"
 
 namespace ast {
 
 // --- CompoundStmt
-CompoundStmt::CompoundStmt( const CompoundStmt& o ) : Stmt(o), kids(o.kids) {
-	assert(!"implemented");
+CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids(other.kids) {
+	// when cloning a compound statement, we may end up cloning declarations which
+	// are referred to by VariableExprs throughout the block. Cloning a VariableExpr
+	// does a shallow copy, so the VariableExpr will end up pointing to the original
+	// declaration. If the original declaration is deleted, e.g. because the original
+	// CompoundStmt is deleted, then we have a dangling pointer. To avoid this case,
+	// find all DeclarationWithType nodes (since a VariableExpr must point to a
+	// DeclarationWithType) in the original CompoundStmt and map them to the cloned
+	// node in the new CompoundStmt ('this'), then replace the Declarations referred to
+	// by each VariableExpr according to the constructed map. Note that only the declarations
+	// in the current level are collected into the map, because child CompoundStmts will
+	// recursively execute this routine. There may be more efficient ways of doing
+	// this.
+	DeclReplacer::DeclMap declMap;
+	auto origit = other.kids.begin();
+	for ( const Stmt * s : kids ) {
+		assert( origit != other.kids.end() );
+		const Stmt * origStmt = *origit++;
+		if ( const DeclStmt * declStmt = dynamic_cast< const DeclStmt * >( s ) ) {
+			const DeclStmt * origDeclStmt = strict_dynamic_cast< const DeclStmt * >( origStmt );
+			if ( const DeclWithType * dwt = dynamic_cast< const DeclWithType * > ( declStmt->decl.get() ) ) {
+				const DeclWithType * origdwt = strict_dynamic_cast< const DeclWithType * > ( origDeclStmt->decl.get() );
+				assert( dwt->name == origdwt->name );
+				declMap[ origdwt ] = dwt;
+			} else assert( ! dynamic_cast< const DeclWithType * > ( origDeclStmt->decl.get() ) );
+		} else assert( ! dynamic_cast< const DeclStmt * > ( s ) );
+	}
+	if ( ! declMap.empty() ) {
+		DeclReplacer::replace( this, declMap );
+	}
 }
 
