Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/AST/Convert.cpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -656,4 +656,10 @@
 	}
 
+	const ast::Stmt * visit( const ast::CoforStmt * node ) override final {
+		// There is no old-AST CoforStmt, so this should never be called.
+		assert( !node );
+		return nullptr;
+	}
+
 	TypeSubstitution * convertTypeSubstitution(const ast::TypeSubstitution * src) {
 
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/AST/Fwd.hpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -68,4 +68,5 @@
 class MutexStmt;
 class CorunStmt;
+class CoforStmt;
 
 class Expr;
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/AST/Node.cpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -194,4 +194,6 @@
 template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::CorunStmt, ast::Node::ref_type::strong >;
+template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::weak >;
+template class ast::ptr_base< ast::CoforStmt, ast::Node::ref_type::strong >;
 template class ast::ptr_base< ast::Expr, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::Expr, ast::Node::ref_type::strong >;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/AST/Pass.hpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -172,4 +172,5 @@
 	const ast::Stmt *             visit( const ast::MutexStmt            * ) override final;
 	const ast::Stmt *             visit( const ast::CorunStmt            * ) override final;
+	const ast::Stmt *             visit( const ast::CoforStmt            * ) override final;
 	const ast::Expr *             visit( const ast::ApplicationExpr      * ) override final;
 	const ast::Expr *             visit( const ast::UntypedExpr          * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/AST/Pass.impl.hpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -1134,4 +1134,22 @@
 
 //--------------------------------------------------------------------------
+// CoforStmt
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::CoforStmt * node ) {
+	VISIT_START( node );
+
+	if ( __visit_children() ) {
+		// for statements introduce a level of scope (for the initialization)
+		guard_symtab guard { *this };
+		maybe_accept( node, &CoforStmt::inits );
+		maybe_accept_top( node, &CoforStmt::cond  );
+		maybe_accept_top( node, &CoforStmt::inc   );
+		maybe_accept_as_compound( node, &CoforStmt::body  );
+	}
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
 // ApplicationExpr
 template< typename core_t >
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/AST/Print.cpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -934,4 +934,46 @@
 	}
 
+	virtual const ast::Stmt * visit( const ast::CoforStmt * node ) override final {
+		os << "Cofor Statement" << endl;
+
+		if ( ! node->inits.empty() ) {
+			os << indent << "... initialization:" << endl;
+			++indent;
+			for ( const ast::Stmt * stmt : node->inits ) {
+				os << indent+1;
+				safe_print( stmt );
+			}
+			--indent;
+		}
+
+		if ( node->cond ) {
+			os << indent << "... condition:" << endl;
+			++indent;
+			os << indent;
+			node->cond->accept( *this );
+			--indent;
+		}
+
+		if ( node->inc ) {
+			os << indent << "... increment:" << endl;
+			++indent;
+			os << indent;
+			node->inc->accept( *this );
+			--indent;
+		}
+
+		if ( node->body ) {
+			os << indent << "... with body:" << endl;
+			++indent;
+			os << indent;
+			node->body->accept( *this );
+			--indent;
+		}
+		os << endl;
+		print( node->labels );
+
+		return node;
+	}
+
 	virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) override final {
 		++indent;
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/AST/Stmt.hpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -546,4 +546,22 @@
 };
 
+// Corun Statement
+class CoforStmt final : public Stmt {
+  public:
+	std::vector<ptr<Stmt>> inits;
+	ptr<Expr> cond;
+	ptr<Expr> inc;
+	ptr<Stmt> body;
+
+	CoforStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * cond,
+			 const Expr * inc, const Stmt * body, const std::vector<Label> && label = {} )
+		: Stmt(loc, std::move(label)), inits(std::move(inits)), cond(cond), inc(inc), body(body) {}
+
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+  private:
+	CoforStmt * clone() const override { return new CoforStmt{ *this }; }
+	MUTATE_FRIEND
+};
+
 } // namespace ast
 
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/AST/Visitor.hpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -60,4 +60,5 @@
     virtual const ast::Stmt *             visit( const ast::MutexStmt            * ) = 0;
     virtual const ast::Stmt *             visit( const ast::CorunStmt            * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::CoforStmt            * ) = 0;
     virtual const ast::Expr *             visit( const ast::ApplicationExpr      * ) = 0;
     virtual const ast::Expr *             visit( const ast::UntypedExpr          * ) = 0;
Index: src/Common/CodeLocationTools.cpp
===================================================================
--- src/Common/CodeLocationTools.cpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/Common/CodeLocationTools.cpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -138,4 +138,5 @@
     macro(MutexStmt, Stmt) \
     macro(CorunStmt, Stmt) \
+	macro(CoforStmt, Stmt) \
     macro(ApplicationExpr, Expr) \
     macro(UntypedExpr, Expr) \
Index: src/Concurrency/Corun.cpp
===================================================================
--- src/Concurrency/Corun.cpp	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/Concurrency/Corun.cpp	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -27,9 +27,19 @@
 struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> {
     UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
+    UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
+    // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
     UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
+    
+    string coforArgName = "__CFA_cofor_lambda_arg";
+    string numProcsName = "__CFA_cofor_num_procs";
+    string currProcsName = "__CFA_cofor_curr_procs";
+    string thdArrName = "__CFA_cofor_thread_array";
+    string loopTempName = "__CFA_cofor_loop_temp";
+    
 
     const StructDecl * runnerBlockDecl = nullptr;
-
-    // Finds select_node decl
+    const StructDecl * coforRunnerDecl = nullptr;
+
+    // Finds runner_block (corun task) and cofor_runner (cofor task) decls
     void previsit( const StructDecl * decl ) {
         if ( !decl->body ) {
@@ -38,9 +48,203 @@
             assert( !runnerBlockDecl );
             runnerBlockDecl = decl;
+        } else if ( "cofor_runner" == decl->name ) {
+            assert( !coforRunnerDecl );
+            coforRunnerDecl = decl;
         }
     }
 
+    // codegen for cofor statements
+    Stmt * postvisit( const CoforStmt * stmt ) {
+        if ( !runnerBlockDecl || !coforRunnerDecl )
+            SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>\n" );
+
+        if ( stmt->inits.size() != 1 )
+            SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control\n" );
+
+        if ( !stmt->body )
+            return nullptr;
+
+        const CodeLocation & loc = stmt->location;
+        const string fnName = CoforFnNamer.newName();
+
+        CompoundStmt * body = new CompoundStmt( loc );
+
+        // push back cofor initializer to generated body
+        body->push_back( deepCopy( stmt->inits.at(0) ) );
+
+        CompoundStmt * fnBody = new CompoundStmt( loc );
+
+        const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
+        if ( ! declStmtPtr )
+            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?\n" );
+
+        const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
+        if ( ! declPtr )
+            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?\n" );
+
+        Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
+
+        // Generates:
+        // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
+        fnBody->push_back( new DeclStmt( loc, 
+            new ObjectDecl( loc,
+                declPtr->name,
+                initType,
+                new SingleInit( loc,
+                    UntypedExpr::createDeref( loc,
+                        new CastExpr( loc, 
+                            new NameExpr( loc, coforArgName ), 
+                            new PointerType( initType ), ExplicitCast
+                        )
+                    )
+                )
+            )
+        ));
+
+        // push rest of cofor body into loop lambda
+        fnBody->push_back( deepCopy( stmt->body ) );
+
+        // Generates:
+        // void __CFA_cofor_lambda_() {
+        //    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
+        //    stmt->body;
+        // }
+        Stmt * coforLambda = new DeclStmt( loc,
+            new FunctionDecl( loc,
+                fnName,                                             // name
+                {},                                                 // forall
+                {
+                    new ObjectDecl( loc,
+                        coforArgName,
+                        new ast::PointerType( new ast::VoidType() )
+                    )
+                },                                                  // params
+                {},                                                 // return
+                fnBody   // body
+            )
+        );
+        body->push_back( coforLambda );
+
+        // Generates:
+        // unsigned __CFA_cofor_num_procs = get_proc_count();
+        body->push_back( new DeclStmt( loc,
+                new ObjectDecl( loc,
+                    numProcsName,
+                    new BasicType( BasicType::Kind::UnsignedInt ),
+                    new SingleInit( loc, 
+                        new UntypedExpr( loc,
+                            new NameExpr( loc, "get_proc_count" ),
+                            {}
+                        )
+                    )
+                )
+            )
+        );
+
+        // Generates:
+        // unsigned __CFA_cofor_curr_procs = 0;
+        body->push_back( new DeclStmt( loc,
+                new ObjectDecl( loc,
+                    currProcsName,
+                    new BasicType( BasicType::Kind::UnsignedInt ),
+                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
+                )
+            )
+        );
+
+        // Generates:
+        // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
+        body->push_back( new DeclStmt( loc,
+                new ObjectDecl( loc,
+                    thdArrName,
+                    new ast::ArrayType(
+                        new StructInstType( coforRunnerDecl ),
+                        new NameExpr( loc, numProcsName ),
+                        ast::FixedLen,
+                        ast::DynamicDim
+                    )
+                )
+            )
+        );
+
+        // Generates:
+        // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
+        body->push_back( new ExprStmt( loc,
+            new UntypedExpr( loc,
+                new NameExpr( loc, "start_runners" ),
+                {
+                    new NameExpr( loc, thdArrName ),
+                    new NameExpr( loc, numProcsName ),
+                    new NameExpr( loc, fnName )
+                }
+            )
+        ));
+
+        // Generates:
+        // typeof(initializer) * __CFA_cofor_loop_temp = malloc();
+        CompoundStmt * forLoopBody = new CompoundStmt( loc );
+        forLoopBody->push_back( new DeclStmt( loc,
+                new ObjectDecl( loc,
+                    loopTempName,
+                    new PointerType( initType ),
+                    new SingleInit( loc, 
+                        new UntypedExpr( loc,
+                            new NameExpr( loc, "malloc" ),
+                            {}
+                        )
+                    )
+                )
+            )
+        );
+
+        // Generates:
+        // *__CFA_cofor_loop_temp = initializer;
+        forLoopBody->push_back( new ExprStmt( loc,
+            UntypedExpr::createAssign( loc,
+                UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
+                new NameExpr( loc, declPtr->name )
+            )
+        ));
+
+        // Generates:
+        // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
+        //     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
+        forLoopBody->push_back( new ExprStmt( loc,
+            new UntypedExpr( loc,
+                new NameExpr( loc, "send_work" ),
+                {
+                    new NameExpr( loc, thdArrName ),
+                    new NameExpr( loc, numProcsName ),
+                    new NameExpr( loc, currProcsName ),
+                    new NameExpr( loc, loopTempName )
+                }
+            )
+        ));
+
+        body->push_back( new ForStmt( loc,
+            {},
+            deepCopy( stmt->cond ),
+            deepCopy( stmt->inc ),
+            forLoopBody
+        ));
+
+        // Generates:
+        // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
+        body->push_back( new ExprStmt( loc,
+            new UntypedExpr( loc,
+                new NameExpr( loc, "end_runners" ),
+                {
+                    new NameExpr( loc, thdArrName ),
+                    new NameExpr( loc, numProcsName )
+                }
+            )
+        ));
+
+        return body;
+    }
+
+    // codegen for corun statements
     Stmt * postvisit( const CorunStmt * stmt ) {
-        if ( !runnerBlockDecl )
+        if ( !runnerBlockDecl || !coforRunnerDecl )
             SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>\n" );
 
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/Parser/StatementNode.cc	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -503,4 +503,23 @@
 } // build_corun
 
+ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt ) {
+	std::vector<ast::ptr<ast::Stmt>> astinit;						// maybe empty
+	buildMoveList( forctl->init, astinit );
+
+	ast::Expr * astcond = nullptr;						// maybe empty
+	astcond = notZeroExpr( maybeMoveBuild( forctl->condition ) );
+
+	ast::Expr * astincr = nullptr;						// maybe empty
+	astincr = maybeMoveBuild( forctl->change );
+	delete forctl;
+
+	return new ast::CoforStmt( location,
+		std::move( astinit ),
+		astcond,
+		astincr,
+		buildMoveSingle( stmt )
+	);
+} // build_cofor
+
 // Local Variables: //
 // tab-width: 4 //
Index: src/Parser/StatementNode.h
===================================================================
--- src/Parser/StatementNode.h	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/Parser/StatementNode.h	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -106,2 +106,3 @@
 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
 ast::Stmt * build_corun( const CodeLocation &, StatementNode * stmt );
+ast::Stmt * build_cofor( const CodeLocation & location, ForCtrl * forctl, StatementNode * stmt );
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 49ae2bc61cd203a75f4b8322e30ede41a6c617cd)
+++ src/Parser/parser.yy	(revision fe293bfa0588f03d55cf5d5b2530f2d0d4d8fc09)
@@ -1725,5 +1725,5 @@
 cofor_statement:
 	COFOR '(' for_control_expression_list ')' statement
-		{ SemanticError( yylloc, "cofor statement is currently unimplemented." ); $$ = nullptr; }
+		{ $$ = new StatementNode( build_cofor( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
 	;
 
