Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Convert.cpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -585,4 +585,10 @@
 	}
 
+    const ast::WhenClause * visit( const ast::WhenClause * node ) override final {
+		// There is no old-AST WhenClause, so this should never be called.
+		assert( !node );
+		return nullptr;
+	}
+
 	const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
 		if ( inCache( node ) ) return nullptr;
@@ -591,9 +597,9 @@
 		for ( auto clause : node->clauses ) {
 			stmt->clauses.push_back({{
-					get<Expression>().accept1( clause->target_func ),
+					get<Expression>().accept1( clause->target ),
 					get<Expression>().acceptL( clause->target_args ),
 				},
 				get<Statement>().accept1( clause->stmt ),
-				get<Expression>().accept1( clause->cond ),
+				get<Expression>().accept1( clause->when_cond ),
 			});
 		}
@@ -612,4 +618,10 @@
 	const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final {
 		// There is no old-AST WaitForClause, so this should never be called.
+		assert( !node );
+		return nullptr;
+	}
+
+    const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
+        // There is no old-AST WaitUntilStmt, so this should never be called.
 		assert( !node );
 		return nullptr;
@@ -2199,8 +2211,8 @@
 			auto clause = new ast::WaitForClause( old->location );
 
-			clause->target_func = GET_ACCEPT_1(clauses[i].target.function, Expr);
+			clause->target = GET_ACCEPT_1(clauses[i].target.function, Expr);
 			clause->target_args = GET_ACCEPT_V(clauses[i].target.arguments, Expr);
 			clause->stmt = GET_ACCEPT_1(clauses[i].statement, Stmt);
-			clause->cond = GET_ACCEPT_1(clauses[i].condition, Expr);
+			clause->when_cond = GET_ACCEPT_1(clauses[i].condition, Expr);
 
 			stmt->clauses.push_back( clause );
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Fwd.hpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -59,6 +59,8 @@
 class FinallyClause;
 class SuspendStmt;
+class WhenClause;
 class WaitForStmt;
 class WaitForClause;
+class WaitUntilStmt;
 class WithStmt;
 class DeclStmt;
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Node.cpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -176,8 +176,12 @@
 template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::strong >;
+template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::weak >;
+template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::strong >;
 template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::strong >;
 template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::strong >;
+template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::weak >;
+template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::strong >;
 template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::strong >;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Pass.hpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -163,6 +163,8 @@
 	const ast::FinallyClause *    visit( const ast::FinallyClause        * ) override final;
 	const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
+    const ast::WhenClause *       visit( const ast::WhenClause           * ) override final;
 	const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
 	const ast::WaitForClause *    visit( const ast::WaitForClause        * ) override final;
+    const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) override final;
 	const ast::Decl *             visit( const ast::WithStmt             * ) override final;
 	const ast::NullStmt *         visit( const ast::NullStmt             * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Pass.impl.hpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -22,5 +22,4 @@
 #include "AST/TranslationUnit.hpp"
 #include "AST/TypeSubstitution.hpp"
-#include "Common/Iterate.hpp"
 
 #define VISIT_START( node ) \
@@ -127,10 +126,4 @@
 	}
 
-	template< typename node_t >
-	template< typename object_t, typename super_t, typename field_t >
-	void __pass::result1< node_t >::apply( object_t * object, field_t super_t::* field ) {
-		object->*field = value;
-	}
-
 	template< typename core_t >
 	template< typename node_t >
@@ -234,54 +227,4 @@
 
 		return {true, compound};
-	}
-
-	template< template <class...> class container_t >
-	template< typename object_t, typename super_t, typename field_t >
-	void __pass::resultNstmt<container_t>::apply(object_t * object, field_t super_t::* field) {
-		auto & container = object->*field;
-		__pedantic_pass_assert( container.size() <= values.size() );
-
-		auto cit = enumerate(container).begin();
-
-		container_t<ptr<Stmt>> nvals;
-		for (delta & d : values) {
-			if ( d.is_old ) {
-				__pedantic_pass_assert( cit.idx <= d.old_idx );
-				std::advance( cit, d.old_idx - cit.idx );
-				nvals.push_back( std::move( (*cit).val) );
-			} else {
-				nvals.push_back( std::move(d.new_val) );
-			}
-		}
-
-		container = std::move(nvals);
-	}
-
-	template< template <class...> class container_t >
-	template< template <class...> class incontainer_t >
-	void __pass::resultNstmt< container_t >::take_all( incontainer_t<ptr<Stmt>> * stmts ) {
-		if (!stmts || stmts->empty()) return;
-
-		std::transform(stmts->begin(), stmts->end(), std::back_inserter( values ),
-			[](ast::ptr<ast::Stmt>& stmt) -> delta {
-				return delta( stmt.release(), -1, false );
-			});
-		stmts->clear();
-		differs = true;
-	}
-
-	template< template<class...> class container_t >
-	template< template<class...> class incontainer_t >
-	void __pass::resultNstmt< container_t >::take_all( incontainer_t<ptr<Decl>> * decls ) {
-		if (!decls || decls->empty()) return;
-
-		std::transform(decls->begin(), decls->end(), std::back_inserter( values ),
-			[](ast::ptr<ast::Decl>& decl) -> delta {
-				auto loc = decl->location;
-				auto stmt = new DeclStmt( loc, decl.release() );
-				return delta( stmt, -1, false );
-			});
-		decls->clear();
-		differs = true;
 	}
 
@@ -353,20 +296,4 @@
 
 		return new_kids;
-	}
-
-	template< template <class...> class container_t, typename node_t >
-	template< typename object_t, typename super_t, typename field_t >
-	void __pass::resultN<container_t, node_t>::apply(object_t * object, field_t super_t::* field) {
-		auto & container = object->*field;
-		__pedantic_pass_assert( container.size() == values.size() );
-
-		for(size_t i = 0; i < container.size(); i++) {
-			// Take all the elements that are different in 'values'
-			// and swap them into 'container'
-			if( values[i] != nullptr ) swap(container[i], values[i]);
-		}
-
-		// Now the original containers should still have the unchanged values
-		// but also contain the new values
 	}
 
@@ -1097,4 +1024,19 @@
 
 //--------------------------------------------------------------------------
+// WhenClause
+template< typename core_t >
+const ast::WhenClause * ast::Pass< core_t >::visit( const ast::WhenClause * node ) {
+	VISIT_START( node );
+
+	if ( __visit_children() ) {
+		maybe_accept( node, &WhenClause::target );
+		maybe_accept( node, &WhenClause::stmt );
+		maybe_accept( node, &WhenClause::when_cond );
+	}
+
+	VISIT_END( WhenClause, node );
+}
+
+//--------------------------------------------------------------------------
 // WaitForStmt
 template< typename core_t >
@@ -1121,11 +1063,29 @@
 
 	if ( __visit_children() ) {
-		maybe_accept( node, &WaitForClause::target_func );
+		maybe_accept( node, &WaitForClause::target );
 		maybe_accept( node, &WaitForClause::target_args );
 		maybe_accept( node, &WaitForClause::stmt );
-		maybe_accept( node, &WaitForClause::cond );
+		maybe_accept( node, &WaitForClause::when_cond );
 	}
 
 	VISIT_END( WaitForClause, node );
+}
+
+//--------------------------------------------------------------------------
+// WaitUntilStmt
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitUntilStmt * node ) {
+	VISIT_START( node );
+
+	if ( __visit_children() ) {
+		maybe_accept( node, &WaitUntilStmt::clauses );
+		maybe_accept( node, &WaitUntilStmt::timeout_time );
+		maybe_accept( node, &WaitUntilStmt::timeout_stmt );
+		maybe_accept( node, &WaitUntilStmt::timeout_cond );
+		maybe_accept( node, &WaitUntilStmt::else_stmt );
+		maybe_accept( node, &WaitUntilStmt::else_cond );
+	}
+
+	VISIT_END( Stmt, node );
 }
 
@@ -2234,4 +2194,6 @@
 }
 
+#undef __pedantic_pass_assertf
+#undef __pedantic_pass_assert
 #undef VISIT_START
 #undef VISIT_END
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Pass.proto.hpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -17,4 +17,5 @@
 // IWYU pragma: private, include "Pass.hpp"
 
+#include "Common/Iterate.hpp"
 #include "Common/Stats/Heap.h"
 namespace ast {
@@ -24,4 +25,12 @@
 	template<typename node_t> node_t * deepCopy( const node_t * );
 }
+
+#ifdef PEDANTIC_PASS_ASSERT
+#define __pedantic_pass_assert(...) assert (__VA_ARGS__)
+#define __pedantic_pass_assertf(...) assertf(__VA_ARGS__)
+#else
+#define __pedantic_pass_assert(...)
+#define __pedantic_pass_assertf(...)
+#endif
 
 namespace ast::__pass {
@@ -130,5 +139,7 @@
 
 	template< typename object_t, typename super_t, typename field_t >
-	void apply( object_t *, field_t super_t::* field );
+	void apply( object_t * object, field_t super_t::* field ) {
+		object->*field = value;
+	}
 };
 
@@ -150,11 +161,48 @@
 
 	template< typename object_t, typename super_t, typename field_t >
-	void apply( object_t *, field_t super_t::* field );
+	void apply( object_t * object, field_t super_t::* field ) {
+		field_t & container = object->*field;
+		__pedantic_pass_assert( container.size() <= values.size() );
+
+		auto cit = enumerate(container).begin();
+
+		container_t<ptr<Stmt>> nvals;
+		for ( delta & d : values ) {
+			if ( d.is_old ) {
+				__pedantic_pass_assert( cit.idx <= d.old_idx );
+				std::advance( cit, d.old_idx - cit.idx );
+				nvals.push_back( std::move( (*cit).val ) );
+			} else {
+				nvals.push_back( std::move( d.new_val ) );
+			}
+		}
+
+		container = std::move(nvals);
+	}
 
 	template< template<class...> class incontainer_t >
-	void take_all( incontainer_t<ptr<Stmt>> * stmts );
+	void take_all( incontainer_t<ptr<Stmt>> * stmts ) {
+		if ( !stmts || stmts->empty() ) return;
+
+		std::transform( stmts->begin(), stmts->end(), std::back_inserter( values ),
+			[](ast::ptr<ast::Stmt>& stmt) -> delta {
+				return delta( stmt.release(), -1, false );
+			});
+		stmts->clear();
+		differs = true;
+	}
 
 	template< template<class...> class incontainer_t >
-	void take_all( incontainer_t<ptr<Decl>> * decls );
+	void take_all( incontainer_t<ptr<Decl>> * decls ) {
+		if ( !decls || decls->empty() ) return;
+
+		std::transform( decls->begin(), decls->end(), std::back_inserter( values ),
+			[](ast::ptr<ast::Decl>& decl) -> delta {
+				ast::Decl const * d = decl.release();
+				return delta( new DeclStmt( d->location, d ), -1, false );
+			});
+		decls->clear();
+		differs = true;
+	}
 };
 
@@ -166,5 +214,16 @@
 
 	template< typename object_t, typename super_t, typename field_t >
-	void apply( object_t *, field_t super_t::* field );
+	void apply( object_t * object, field_t super_t::* field ) {
+		field_t & container = object->*field;
+		__pedantic_pass_assert( container.size() == values.size() );
+
+		for ( size_t i = 0; i < container.size(); ++i ) {
+			// Take all the elements that are different in 'values'
+			// and swap them into 'container'
+			if ( values[i] != nullptr ) swap(container[i], values[i]);
+		}
+		// Now the original containers should still have the unchanged values
+		// but also contain the new values.
+	}
 };
 
@@ -534,2 +593,5 @@
 
 } // namespace ast::__pass
+
+#undef __pedantic_pass_assertf
+#undef __pedantic_pass_assert
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Print.cpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -208,4 +208,31 @@
 	}
 
+    void print( const ast::WaitStmt * node ) {
+		if ( node->timeout_time ) {
+			os << indent-1 << "timeout of:" << endl;
+			node->timeout_time->accept( *this );
+
+			if ( node->timeout_stmt ) {
+				os << indent-1 << "... with statment:" << endl;
+				node->timeout_stmt->accept( *this );
+			}
+
+			if ( node->timeout_cond ) {
+				os << indent-1 << "... with condition:" << endl;
+				node->timeout_cond->accept( *this );
+			}
+		}
+
+		if ( node->else_stmt ) {
+			os << indent-1 << "else:" << endl;
+			node->else_stmt->accept( *this );
+
+			if ( node->else_cond ) {
+				os << indent-1 << "... with condition:" << endl;
+				node->else_cond->accept( *this );
+			}
+		}
+	}
+
 	void preprint( const ast::NamedTypeDecl * node ) {
 		if ( ! node->name.empty() ) {
@@ -761,4 +788,21 @@
 	}
 
+	virtual const ast::WhenClause * visit( const ast::WhenClause * node ) override final {
+		os << indent-1 << "target: ";
+		safe_print( node->target );
+
+		if ( node->stmt ) {
+			os << indent-1 << "... with statment:" << endl;
+			node->stmt->accept( *this );
+		}
+
+		if ( node->when_cond ) {
+			os << indent-1 << "... with when condition:" << endl;
+			node->when_cond->accept( *this );
+		}
+
+		return node;
+	}
+
 	virtual const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
 		os << "Waitfor Statement" << endl;
@@ -798,5 +842,5 @@
 	virtual const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final {
 		os << indent-1 << "target function: ";
-		safe_print( node->target_func );
+		safe_print( node->target );
 
 		if ( !node->target_args.empty() ) {
@@ -812,9 +856,19 @@
 		}
 
-		if ( node->cond ) {
+		if ( node->when_cond ) {
 			os << indent-1 << "... with condition:" << endl;
-			node->cond->accept( *this );
-		}
-
+			node->when_cond->accept( *this );
+		}
+
+		return node;
+	}
+
+    virtual const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
+		os << "Waituntil Statement" << endl;
+		indent += 2;
+		for( const auto & clause : node->clauses ) {
+			clause->accept( *this );
+		}
+        print(node);    // calls print( const ast::WaitStmt * node )
 		return node;
 	}
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Stmt.hpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -378,9 +378,9 @@
 };
 
-// Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...
-class WaitForStmt final : public Stmt {
-  public:
-	std::vector<ptr<WaitForClause>> clauses;
-	ptr<Expr> timeout_time;
+// Base class of WaitFor/WaitUntil statements
+// form: KEYWORD(...) ... timeout(...) ... else ...
+class WaitStmt : public Stmt { 
+  public:
+    ptr<Expr> timeout_time;
 	ptr<Stmt> timeout_stmt;
 	ptr<Expr> timeout_cond;
@@ -388,6 +388,36 @@
 	ptr<Expr> else_cond;
 
+    WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
+		: Stmt(loc, std::move(labels)) {}
+
+  private:
+    WaitStmt * clone() const override = 0;
+	MUTATE_FRIEND
+};
+
+// Base class for WaitFor/WaitUntil clauses
+// form: when( when_cond ) KEYWORD( target ) stmt
+class WhenClause : public StmtClause {
+  public:
+	ptr<Expr> target;
+	ptr<Stmt> stmt;
+	ptr<Expr> when_cond;
+
+	WhenClause( const CodeLocation & loc )
+		: StmtClause( loc ) {}
+
+	const WhenClause * accept( Visitor & v ) const override { return v.visit( this ); }
+  private:
+	WhenClause * clone() const override { return new WhenClause{ *this }; }
+	MUTATE_FRIEND
+};
+
+// Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...
+class WaitForStmt final : public WaitStmt {
+  public:
+	std::vector<ptr<WaitForClause>> clauses;
+
 	WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
-		: Stmt(loc, std::move(labels)) {}
+		: WaitStmt(loc, std::move(labels)) {}
 
 	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
@@ -398,17 +428,60 @@
 
 // Clause in a waitfor statement: waitfor (..., ...) ...
-class WaitForClause final : public StmtClause {
-  public:
-	ptr<Expr> target_func;
+class WaitForClause final : public WhenClause {
+  public:
 	std::vector<ptr<Expr>> target_args;
-	ptr<Stmt> stmt;
-	ptr<Expr> cond;
 
 	WaitForClause( const CodeLocation & loc )
-		: StmtClause( loc ) {}
+		: WhenClause( loc ) {}
 
 	const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); }
   private:
 	WaitForClause * clone() const override { return new WaitForClause{ *this }; }
+	MUTATE_FRIEND
+};
+
+// waituntil statement: when (...) waituntil (...) ... timeout(...) ... else ...
+class WaitUntilStmt final : public WaitStmt {
+  public:
+    // Non-ast node used during compilation to store data needed to generate predicates
+    //    and set initial status values for clauses
+    // Used to create a tree corresponding to the structure of the clauses in a WaitUntil
+    struct ClauseNode { 
+        enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag
+        // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing
+
+        ClauseNode * left;
+        ClauseNode * right;
+        WhenClause * leaf;  // only set if this node is a leaf (points into vector of clauses)
+
+        bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses
+        bool whenState;     // used to track if when_cond is toggled on or off for generating init values
+        bool childOfAnd;      // true on leaf nodes that are children of AND, false otherwise
+
+        ClauseNode( Op op, ClauseNode * left, ClauseNode * right )
+            : op(op), left(left), right(right), leaf(nullptr), 
+            ambiguousWhen(false), whenState(true), childOfAnd(false) {}
+        ClauseNode( Op op, WhenClause * leaf )
+            : op(op), left(nullptr), right(nullptr), leaf(leaf),
+            ambiguousWhen(false), whenState(true), childOfAnd(false) {}
+        ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}
+        
+        ~ClauseNode() {
+            if ( left ) delete left;
+            if ( right ) delete right;
+        }
+    };
+
+	std::vector<ptr<WhenClause>> clauses;
+    ClauseNode * predicateTree;
+
+	WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
+		: WaitStmt(loc, std::move(labels)) {}
+
+    ~WaitUntilStmt() { delete predicateTree; }
+
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+  private:
+	WaitUntilStmt * clone() const override { return new WaitUntilStmt{ *this }; }
 	MUTATE_FRIEND
 };
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision f4e01f1a8e29b20d612b65cba4f4f8908d914ba8)
+++ src/AST/Visitor.hpp	(revision 044ae62f3758370207e9bd48aa003fbc826b3d4d)
@@ -51,6 +51,8 @@
     virtual const ast::FinallyClause *    visit( const ast::FinallyClause        * ) = 0;
     virtual const ast::Stmt *             visit( const ast::SuspendStmt          * ) = 0;
+    virtual const ast::WhenClause *       visit( const ast::WhenClause           * ) = 0;
     virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
     virtual const ast::WaitForClause *    visit( const ast::WaitForClause        * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) = 0;
     virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
     virtual const ast::NullStmt *         visit( const ast::NullStmt             * ) = 0;
