Index: driver/Makefile.am
===================================================================
--- driver/Makefile.am	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ driver/Makefile.am	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -19,5 +19,5 @@
 
 # applies to both programs
-AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src
+AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src -I${abs_top_srcdir}/src/include
 
 # don't install cfa directly
Index: driver/Makefile.in
===================================================================
--- driver/Makefile.in	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ driver/Makefile.in	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -334,5 +334,5 @@
 
 # applies to both programs
-AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src
+AM_CXXFLAGS = @HOST_FLAGS@ -Wall -O2 -g -std=c++14 -I${abs_top_srcdir}/src -I${abs_top_srcdir}/src/include
 cfa_SOURCES = cfa.cc
 
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Decl.hpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -101,7 +101,7 @@
 	ptr<Expr> bitfieldWidth;
 
-	ObjectDecl( const CodeLocation& loc, const std::string& name, Type* type, Init* init = nullptr,
-		Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, Expr* bitWd = nullptr,
-		std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
+	ObjectDecl( const CodeLocation & loc, const std::string & name, const Type * type, Init * init = nullptr,
+		Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, Expr * bitWd = nullptr,
+		std::vector< ptr<Attribute> > && attrs = {}, Function::Specs fs = {})
 	: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ),
 	  init( init ), bitfieldWidth( bitWd ) {}
Index: src/AST/DeclReplacer.cpp
===================================================================
--- src/AST/DeclReplacer.cpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/DeclReplacer.cpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -14,5 +14,5 @@
 //
 
-#error unimplemented
+#warning unimplemented
 
 // Local Variables: //
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Expr.cpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -95,5 +95,4 @@
 	Type * addrType( const Type * type ) {
 		if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * >( type ) ) {
-			CV::Qualifiers quals = refType->qualifiers;
 			return new ReferenceType{ addrType( refType->base ), refType->qualifiers };
 		} else {
@@ -118,5 +117,5 @@
 				result = res;
 			} else {
-				SemanticError( loc, arg->result,
+				SemanticError( loc, arg->result.get(),
 					"Attempt to take address of non-lvalue expression: " );
 			}
@@ -283,7 +282,7 @@
 // --- ConstructorExpr
 
-ConstructorExpr::ConstructorExpr( const CodeLocation & loc, const Expr * call ) 
+ConstructorExpr::ConstructorExpr( const CodeLocation & loc, const Expr * call )
 : Expr( loc ), callExpr( call ) {
-	// allow resolver to type a constructor used as an expression if it has the same type as its 
+	// allow resolver to type a constructor used as an expression if it has the same type as its
 	// first argument
 	assert( callExpr );
@@ -310,5 +309,5 @@
 TupleIndexExpr::TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i )
 : Expr( loc ), tuple( t ), index( i ) {
-	const TupleType * type = strict_dynamic_cast< const TupleType * >( tuple->result );
+	const TupleType * type = strict_dynamic_cast< const TupleType * >( tuple->result.get() );
 	assertf( type->size() > index, "TupleIndexExpr index out of bounds: tuple size %d, requested "
 		"index %d in expr %s", type->size(), index, toString( tuple ).c_str() );
@@ -319,9 +318,9 @@
 // --- TupleAssignExpr
 
-TupleAssignExpr::TupleAssignExpr( 
-	const CodeLocation & loc, std::vector<ptr<Expr>> && assigns, 
+TupleAssignExpr::TupleAssignExpr(
+	const CodeLocation & loc, std::vector<ptr<Expr>> && assigns,
 	std::vector<ptr<ObjectDecl>> && tempDecls )
 : Expr( loc, Tuples::makeTupleType( assigns ) ), stmtExpr() {
-	// convert internally into a StmtExpr which contains the declarations and produces the tuple of 
+	// convert internally into a StmtExpr which contains the declarations and produces the tuple of
 	// the assignments
 	std::list<ptr<Stmt>> stmts;
@@ -337,5 +336,5 @@
 // --- StmtExpr
 
-StmtExpr::StmtExpr( const CodeLocation & loc, const CompoundStmt * ss ) 
+StmtExpr::StmtExpr( const CodeLocation & loc, const CompoundStmt * ss )
 : Expr( loc ), stmts( ss ), returnDecls(), dtors() { computeResult(); }
 
@@ -344,5 +343,5 @@
 	const std::list<ptr<Stmt>> & body = stmts->kids;
 	if ( ! returnDecls.empty() ) {
-		// prioritize return decl for result type, since if a return decl exists, then the StmtExpr 
+		// prioritize return decl for result type, since if a return decl exists, then the StmtExpr
 		// is currently in an intermediate state where the body will always give a void result type
 		result = returnDecls.front()->get_type();
@@ -360,11 +359,13 @@
 unsigned long long UniqueExpr::nextId = 0;
 
-UniqueExpr::UniqueExpr( const CodeLocation & loc, const Expr * e, unsigned long long i = -1 )
+UniqueExpr::UniqueExpr( const CodeLocation & loc, const Expr * e, unsigned long long i )
 : Expr( loc, e->result ), id( i ) {
 	assert( expr );
-	if ( id == -1 ) {
-		assert( nextId != -1 );
+	if ( id == -1ull ) {
+		assert( nextId != -1ull );
 		id = nextId++;
 	}
+}
+
 }
 
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Fwd.hpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -125,6 +125,4 @@
 class ConstructorInit;
 
-class Constant;
-
 class Label;
 
@@ -135,4 +133,7 @@
 std::string toString( const Node * );
 
+template < typename ... Params >
+std::string toString( const Params & ... params );
+
 typedef unsigned int UniqueId;
 
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Node.cpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -16,8 +16,12 @@
 #include "Node.hpp"
 #include "Fwd.hpp"
+
+#include "Attribute.hpp"
 #include "Decl.hpp"
 #include "Expr.hpp"
+#include "Init.hpp"
 #include "Stmt.hpp"
 #include "Type.hpp"
+#include "TypeSubstitution.hpp"
 
 template< typename node_t, enum ast::Node::ref_type ref_t >
@@ -26,4 +30,17 @@
 template< typename node_t, enum ast::Node::ref_type ref_t >
 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
+
+/// Sets this pointer to a mutated version of a pointer (possibly) owned elsehere.
+/// Returns a mutable version of the pointer in this node.
+template< typename node_t, enum ast::Node::ref_type ref_t >
+node_t * ast::ptr_base<node_t, ref_t>::set_and_mutate( const node_t * n ) {
+	// ensure ownership of `n` by this node to avoid spurious single-owner mutates
+	assign( n );
+	// get mutable version of `n`
+	auto r = mutate( node );
+	// re-assign mutable version in case `mutate()` produced a new pointer
+	assign( r );
+	return r;
+}
 
 template class ast::ptr_base< ast::Node, ast::Node::ref_type::weak >;
@@ -227,6 +244,4 @@
 template class ast::ptr_base< ast::ConstructorInit, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::ConstructorInit, ast::Node::ref_type::strong >;
-template class ast::ptr_base< ast::Constant, ast::Node::ref_type::weak >;
-template class ast::ptr_base< ast::Constant, ast::Node::ref_type::strong >;
 template class ast::ptr_base< ast::Attribute, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::Attribute, ast::Node::ref_type::strong >;
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Node.hpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -143,13 +143,5 @@
 	/// Sets this pointer to a mutated version of a pointer (possibly) owned elsehere.
 	/// Returns a mutable version of the pointer in this node.
-	node_t * set_and_mutate( const node_t * n ) {
-		// ensure ownership of `n` by this node to avoid spurious single-owner mutates
-		assign( n );
-		// get mutable version of `n`
-		auto r = mutate( node );
-		// re-assign mutable version in case `mutate()` produced a new pointer
-		assign( r );
-		return r;
-	}
+	node_t * set_and_mutate( const node_t * n );
 
 	using ptr = const node_t *;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Pass.hpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -175,5 +175,4 @@
 	const ast::Init *             visit( const ast::ListInit             * ) override final;
 	const ast::Init *             visit( const ast::ConstructorInit      * ) override final;
-	const ast::Constant *         visit( const ast::Constant             * ) override final;
 	const ast::Attribute *        visit( const ast::Attribute            * ) override final;
 	const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Pass.impl.hpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -791,4 +791,129 @@
 
 //--------------------------------------------------------------------------
+// CatchStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		// catch statements introduce a level of scope (for the caught exception)
+		guard_indexer guard { *this };
+		maybe_accept( node, &CatchStmt::decl );
+		maybe_accept( node, &CatchStmt::cond );
+		maybe_accept( node, &CatchStmt::body );
+	})
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// FinallyStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &FinallyStmt::body );
+	)
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// WaitForStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
+	VISIT_START( node );
+		// for( auto & clause : node->clauses ) {
+		// 	maybeAccept_impl( clause.target.function, *this );
+		// 	maybeAccept_impl( clause.target.arguments, *this );
+
+		// 	maybeAccept_impl( clause.statement, *this );
+		// 	maybeAccept_impl( clause.condition, *this );
+		// }
+
+	#define maybe_accept(field) \
+		if(node->field) { \
+			auto nval = call_accept( node->field ); \
+			if(nval != node->field ) { \
+				auto nparent = mutate(node); \
+				nparent->field = nval; \
+				node = nparent; \
+			} \
+		}
+
+	VISIT(
+		maybe_accept( timeout.time );
+		maybe_accept( timeout.stmt );
+		maybe_accept( timeout.cond );
+		maybe_accept( orElse.stmt  );
+		maybe_accept( orElse.cond  );
+	)
+
+	#undef maybe_accept
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// WithStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &WithStmt::exprs );
+		{
+			// catch statements introduce a level of scope (for the caught exception)
+			guard_indexer guard { *this };
+			__pass::indexer::addWith( pass, 0, node->exprs, node );
+			maybe_accept( node, &WithStmt::stmt );
+		}
+	)
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// NullStmt
+template< typename pass_t >
+const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
+	VISIT_START( node );
+	VISIT_END( NullStmt, node );
+}
+
+//--------------------------------------------------------------------------
+// DeclStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &DeclStmt::decl );
+	)
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// ImplicitCtorDtorStmt
+template< typename pass_t >
+const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
+	VISIT_START( node );
+
+	// For now this isn't visited, it is unclear if this causes problem
+	// if all tests are known to pass, remove this code
+	// VISIT(
+	// 	maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
+	// )
+
+	VISIT_END( Stmt, node );
+}
+
+
+
+
+
+
+//--------------------------------------------------------------------------
 // SingleInit
 template< typename pass_t >
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Pass.proto.hpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -241,5 +241,6 @@
 		INDEXER_FUNC1( addUnion  , const UnionDecl *     );
 		INDEXER_FUNC1( addTrait  , const TraitDecl *     );
-		INDEXER_FUNC2( addWith   , const std::list< ptr<Expr> > &, const Node * );
+		INDEXER_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
+		INDEXER_FUNC2( addWith   , const std::list  < ptr<Expr> > &, const Node * );
 
 		// A few extra functions have more complicated behaviour, they are hand written
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/AST/Visitor.hpp	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -111,5 +111,4 @@
     virtual const ast::Init *             visit( const ast::ListInit             * ) = 0;
     virtual const ast::Init *             visit( const ast::ConstructorInit      * ) = 0;
-    virtual const ast::Constant *         visit( const ast::Constant             * ) = 0;
     virtual const ast::Attribute *        visit( const ast::Attribute            * ) = 0;
     virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) = 0;
Index: src/Common/SemanticError.h
===================================================================
--- src/Common/SemanticError.h	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/Common/SemanticError.h	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -17,4 +17,5 @@
 
 #include "ErrorObjects.h"
+#include "AST/Node.hpp"
 #include <cstring>
 
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/InitTweak/InitTweak.cc	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -437,5 +437,5 @@
 		// const ast::Expr * callArg( const CallExpr * call, unsigned int pos ) {
 		// 	if( pos >= call->args.size() ) {
-		// 		assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.", 
+		// 		assertf( false, "getCallArg for argument that doesn't exist: (%u); %s.",
 		// 			pos, toString( call ).c_str() );
 		// 	}
@@ -467,5 +467,8 @@
 	}
 	const ast::Expr * getCallArg( const ast::Expr * call, unsigned pos ) {
-		assert(!"implemented; needs to build AST/Expr.cpp");
+		(void)call;
+		(void)pos;
+		#warning unimplemented; needs to build AST/Expr.cpp
+		assertf(false, "unimplemented; needs to build AST/Expr.cpp");
 		// if ( auto app = dynamic_cast< const ast::ApplicationExpr * >( call ) ) {
 		// 	return callArg( app, pos );
@@ -482,5 +485,5 @@
 		// 	return getCallArg( ctor->callExpr, pos );
 		// } else {
-		// 	assertf( false, "Unexpected expression type passed to getCallArg: %s", 
+		// 	assertf( false, "Unexpected expression type passed to getCallArg: %s",
 		// 		toString( call ).c_str() );
 		// }
@@ -548,5 +551,7 @@
 	}
 	const ast::Type* getPointerBase( const ast::Type* t ) {
-		assert(!"needs to build Type.cpp before inclusion");
+		(void)t;
+		#warning needs to build Type.cpp before inclusion
+		assertf(false, "needs to build Type.cpp before inclusion");
 		// if ( const auto * p = dynamic_cast< const ast::PointerType * >( t ) ) {
 		// 	return p->base;
Index: src/SynTree/Declaration.cc
===================================================================
--- src/SynTree/Declaration.cc	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/SynTree/Declaration.cc	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -31,9 +31,9 @@
 
 Declaration::Declaration( const std::string &name, Type::StorageClasses scs, LinkageSpec::Spec linkage )
-		: name( name ), linkage( linkage ), storageClasses( scs ), uniqueId( 0 ) {
+		: name( name ), linkage( linkage ), uniqueId( 0 ), storageClasses( scs ) {
 }
 
 Declaration::Declaration( const Declaration &other )
-	: BaseSyntaxNode( other ), name( other.name ), linkage( other.linkage ), extension( other.extension ), storageClasses( other.storageClasses ), uniqueId( other.uniqueId ) {
+	: BaseSyntaxNode( other ), name( other.name ), linkage( other.linkage ), extension( other.extension ), uniqueId( other.uniqueId ), storageClasses( other.storageClasses ) {
 }
 
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/Tuples/TupleExpansion.cc	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -320,11 +320,13 @@
 	}
 	const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
-		assert(!"implemented; needs Type.cpp in build");
+		(void) exprs;
+		#warning Not implemented; needs Type.cpp in build
+		assertf(false, "Not implemented; needs Type.cpp in build");
 		// // produce the TupleType which aggregates the types of the exprs
 		// std::vector<ast::ptr<ast::Type>> types;
-		// ast::CV::Qualifiers quals{ 
-		// 	ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue | 
+		// ast::CV::Qualifiers quals{
+		// 	ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
 		// 	ast::CV::Atomic | ast::CV::Mutex };
-		
+
 		// for ( const ast::Expr * expr : exprs ) {
 		// 	assert( expr->result );
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision d66e7b7b110efcf99370d5d03e97d25793df250a)
+++ src/Tuples/Tuples.h	(revision 896737bef2a0b30fad7d7e9a0b8989c1324a5d40)
@@ -29,7 +29,7 @@
 namespace Tuples {
 	// TupleAssignment.cc
-	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 
+	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
 		std::vector< ResolvExpr::AlternativeFinder >& args );
-	
+
 	// TupleExpansion.cc
 	/// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
@@ -48,4 +48,5 @@
 	/// returns a TypeInstType if `type` is a ttype, nullptr otherwise
 	TypeInstType * isTtype( Type * type );
+	const ast::TypeInstType * isTtype( const ast::Type * type );
 
 	/// returns true if the expression may contain side-effects.
