Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/AST/Fwd.hpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -49,4 +49,5 @@
 class WhileDoStmt;
 class ForStmt;
+class ForeachStmt;
 class SwitchStmt;
 class CaseClause;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/AST/Pass.hpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -138,4 +138,5 @@
 	const ast::Stmt *             visit( const ast::WhileDoStmt          * ) override final;
 	const ast::Stmt *             visit( const ast::ForStmt              * ) override final;
+	const ast::Stmt *             visit( const ast::ForeachStmt          * ) override final;
 	const ast::Stmt *             visit( const ast::SwitchStmt           * ) override final;
 	const ast::CaseClause *       visit( const ast::CaseClause           * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/AST/Pass.impl.hpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -803,7 +803,25 @@
 		maybe_accept_top( node, &ForStmt::cond  );
 		maybe_accept_top( node, &ForStmt::inc   );
-		maybe_accept_top( node, &ForStmt::range_over );
 		maybe_accept_as_compound( node, &ForStmt::body  );
 		maybe_accept_as_compound( node, &ForStmt::else_ );
+	}
+
+	VISIT_END( Stmt, node );
+}
+
+//--------------------------------------------------------------------------
+// ForeachStmt
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForeachStmt * node ) {
+	VISIT_START( node );
+
+	if ( __visit_children() ) {
+		// for statements introduce a level of scope (for the initialization)
+		guard_symtab guard { *this };
+		// xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later.
+		maybe_accept( node, &ForeachStmt::inits );
+		maybe_accept_top( node, &ForeachStmt::range );
+		maybe_accept_as_compound( node, &ForeachStmt::body  );
+		maybe_accept_as_compound( node, &ForeachStmt::else_ );
 	}
 
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/AST/Print.cpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -637,4 +637,52 @@
 	}
 
+	virtual const ast::Stmt * visit( const ast::ForeachStmt * node ) override final {
+		os << "Range for 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->isIncreasing ) {
+			os << indent << "increasing" << endl;
+		} else {
+			os << indent << "decreasing" << endl;
+		}
+
+		if ( !node->range ) {
+			os << indent << "... over range:" << endl;
+			++indent;
+			node->range->accept( *this );
+			--indent;
+		}
+
+		if ( node->body ) {
+			os << indent << "... with body:" << endl;
+			++indent;
+			os << indent;
+			node->body->accept( *this );
+			--indent;
+		}
+
+		if ( node->else_ ) {
+			os << indent << "... with else:" << endl;
+			++indent;
+			os << indent;
+			node->else_->accept( *this );
+			--indent;
+		}
+
+		os << endl;
+		print( node->labels );
+
+		return node;
+	}
+
 	virtual const ast::Stmt * visit( const ast::SwitchStmt * node ) override final {
 		os << "Switch on condition: ";
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/AST/Stmt.hpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -237,6 +237,4 @@
 	ptr<Expr> cond;
 	ptr<Expr> inc;
-	ptr<Expr> range_over;
-	bool is_inc;
 	ptr<Stmt> body;
 	ptr<Stmt> else_;
@@ -245,14 +243,9 @@
 			 const Expr * inc, const Stmt * body, const std::vector<Label> && label = {} )
 		: Stmt(loc, std::move(label)), inits(std::move(inits)), cond(cond), inc(inc),
-			range_over(nullptr), body(body), else_(nullptr) {}
+		body(body), else_(nullptr) {}
 
 	ForStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * cond,
 			 const Expr * inc, const Stmt * body, const Stmt * else_, const std::vector<Label> && labels = {} )
 		: Stmt(loc, std::move(labels)), inits(std::move(inits)), cond(cond), inc(inc),
-			range_over(nullptr), body(body), else_(else_) {}
-
-	ForStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits, const Expr * range_over, bool is_inc,
-			 const Stmt * body, const Stmt * else_ )
-		: Stmt(loc, std::move(labels)), inits(std::move(inits)), range_over(range_over), is_inc(is_inc), 
 		body(body), else_(else_) {}
 
@@ -260,4 +253,27 @@
   private:
 	ForStmt * clone() const override { return new ForStmt{ *this }; }
+	MUTATE_FRIEND
+};
+
+enum RangeDirection { DecreasingRange, IncreasingRange };
+
+// For-each loop: for (... : ...) ... else ...
+class ForeachStmt final : public Stmt {
+  public:
+	std::vector<ptr<Stmt>> inits;
+	ptr<Expr> range;
+	ptr<Stmt> body;
+	ptr<Stmt> else_;
+	// This is a property of the range, but there is no place to store it.
+	RangeDirection isIncreasing;
+
+	ForeachStmt( const CodeLocation & loc, const std::vector<ptr<Stmt>> && inits,
+			const Expr * range_over, RangeDirection isInc, const Stmt * body, const Stmt * else_ )
+		: Stmt(loc, std::move(labels)), inits(std::move(inits)), range(range_over),
+		body(body), else_(else_), isIncreasing(isInc) {}
+
+	const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
+  private:
+	ForeachStmt * clone() const override { return new ForeachStmt{ *this }; }
 	MUTATE_FRIEND
 };
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/AST/Visitor.hpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -41,4 +41,5 @@
     virtual const ast::Stmt *             visit( const ast::WhileDoStmt          * ) = 0;
     virtual const ast::Stmt *             visit( const ast::ForStmt              * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::ForeachStmt          * ) = 0;
     virtual const ast::Stmt *             visit( const ast::SwitchStmt           * ) = 0;
     virtual const ast::CaseClause *       visit( const ast::CaseClause           * ) = 0;
Index: src/Common/CodeLocationTools.cpp
===================================================================
--- src/Common/CodeLocationTools.cpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/Common/CodeLocationTools.cpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -119,4 +119,5 @@
     macro(WhileDoStmt, Stmt) \
     macro(ForStmt, Stmt) \
+    macro(ForeachStmt, Stmt) \
     macro(SwitchStmt, Stmt) \
     macro(CaseClause, CaseClause) \
Index: src/ControlStruct/TranslateEnumRange.cpp
===================================================================
--- src/ControlStruct/TranslateEnumRange.cpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/ControlStruct/TranslateEnumRange.cpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -9,30 +9,25 @@
 
 struct TranslateEnumRangeCore {
-	const ast::Stmt * postvisit( const ast::ForStmt * stmt );
+	const ast::Stmt * postvisit( const ast::ForeachStmt * stmt );
 };
 
-const ast::Stmt * TranslateEnumRangeCore::postvisit( const ast::ForStmt * stmt ) {
-	if ( !stmt->range_over ) return stmt;
-	auto mutStmt = ast::mutate( stmt );
-	auto & location = mutStmt->location;
+const ast::Stmt * TranslateEnumRangeCore::postvisit( const ast::ForeachStmt * stmt ) {
+	auto & location = stmt->location;
 
-	if ( auto declStmt = mutStmt->inits.front().as<ast::DeclStmt>() ) {
-		if ( auto objDecl = declStmt->decl.as<ast::ObjectDecl>() ) {
-			if ( !objDecl->init ) {
-				ast::SingleInit * newInit = new ast::SingleInit( location,
-					ast::UntypedExpr::createCall( location,
-						mutStmt->is_inc ? "lowerBound" : "upperBound", {} ),
-					ast::ConstructFlag::MaybeConstruct
-				);
-				auto objDeclWithInit = ast::mutate_field( objDecl, &ast::ObjectDecl::init, newInit );
-				auto declWithInit = ast::mutate_field( declStmt, &ast::DeclStmt::decl, objDeclWithInit );
-				mutStmt->inits[0] = declWithInit;
-			}
-		}
+	assert( stmt->inits.size() == 1 );
+	ast::DeclStmt const * initialize = stmt->inits.front().strict_as<ast::DeclStmt>();
+
+	auto objDecl = initialize->decl.strict_as<ast::ObjectDecl>();
+	if ( !objDecl->init ) {
+		ast::SingleInit * init = new ast::SingleInit( location,
+			ast::UntypedExpr::createCall( location,
+				stmt->isIncreasing ? "lowerBound" : "upperBound", {} ),
+			ast::ConstructFlag::MaybeConstruct
+		);
+		objDecl = ast::mutate_field( objDecl, &ast::ObjectDecl::init, init );
+		initialize = ast::mutate_field( initialize, &ast::DeclStmt::decl, objDecl );
 	}
 
-	auto declStmt = mutStmt->inits.front().strict_as<ast::DeclStmt>();
-	auto initDecl = declStmt->decl.strict_as<ast::ObjectDecl>();
-	auto indexName = initDecl->name;
+	auto indexName = objDecl->name;
 
 	// Both inc and dec check if the current posn less than the number of enumerator
@@ -40,18 +35,25 @@
 	// it wraps around and become unsigned max
 	ast::UntypedExpr * condition = ast::UntypedExpr::createCall( location,
-		mutStmt->is_inc ? "?<=?" : "?>=?",
+		stmt->isIncreasing ? "?<=?" : "?>=?",
 		{
 			new ast::NameExpr( location, indexName ),
 			ast::UntypedExpr::createCall( location,
-				mutStmt->is_inc ? "upperBound" : "lowerBound", {} )
+				stmt->isIncreasing ? "upperBound" : "lowerBound", {} )
 		} );
-	auto increment = ast::UntypedExpr::createCall( location,
-		mutStmt->is_inc ? "succ_unsafe" : "pred_unsafe",
-		{ new ast::NameExpr( location, indexName ) } );
-	auto assig = ast::UntypedExpr::createAssign( location,
-		new ast::NameExpr( location, indexName ), increment );
-	mutStmt->cond = condition;
-	mutStmt->inc = assig;
-	return mutStmt;
+	ast::UntypedExpr * increment = ast::UntypedExpr::createAssign( location,
+		new ast::NameExpr( location, indexName ),
+		ast::UntypedExpr::createCall( location,
+			stmt->isIncreasing ? "succ_unsafe" : "pred_unsafe",
+			{ new ast::NameExpr( location, indexName ) } ) );
+
+	return new ast::ForStmt(
+		stmt->location,
+		{ initialize },
+		condition,
+		increment,
+		stmt->body,
+		stmt->else_,
+		copy( stmt->labels )
+	);
 }
 
Index: src/Parser/StatementNode.cpp
===================================================================
--- src/Parser/StatementNode.cpp	(revision b723b630250eb742c4fe13ca63afabe6f0ad2e3c)
+++ src/Parser/StatementNode.cpp	(revision fca78f10fcf2198f57e0f9e7ea3fe351ee91befa)
@@ -213,9 +213,11 @@
 	if ( forctl->range_over ) {
 		ast::Expr * range_over = maybeMoveBuild( forctl->range_over );
-		auto kind = forctl->kind;						// save before delete, used in return
+		bool isIncreasing = forctl->kind == OperKinds::LEThan;
+		// Copy all the data needed before the delete.
 		delete forctl;
-		return new ast::ForStmt( location,
+		return new ast::ForeachStmt( location,
 			std::move( astinit ),
-			range_over, kind == OperKinds::LEThan,
+			range_over,
+			isIncreasing ? ast::IncreasingRange : ast::DecreasingRange,
 			buildMoveSingle( stmt ),
 			buildMoveOptional( else_ )
