Index: src/ControlStruct/MLEMutator.cc
===================================================================
--- src/ControlStruct/MLEMutator.cc	(revision a16764a6fbfe44300fc8834400a31c89befda091)
+++ src/ControlStruct/MLEMutator.cc	(revision c28bcc70dd18798fb233be8674960aa1fd57e47e)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Aug  4 11:21:32 2016
-// Update Count     : 202
+// Last Modified On : Thu Mar  8 17:08:25 2018
+// Update Count     : 219
 //
 
@@ -38,13 +38,33 @@
 	}
 	namespace {
-		Statement * isLoop( Statement * stmt ) { return dynamic_cast< WhileStmt * >( stmt ) ? stmt : dynamic_cast< ForStmt * >( stmt ) ? stmt : 0; }
-	}
+		bool isLoop( const MLEMutator::Entry & e ) { return dynamic_cast< WhileStmt * >( e.get_controlStructure() ) || dynamic_cast< ForStmt * >( e.get_controlStructure() ); }
+		bool isSwitch( const MLEMutator::Entry & e ) { return dynamic_cast< SwitchStmt *>( e.get_controlStructure() ); }
+
+		bool isBreakTarget( const MLEMutator::Entry & e ) { return isLoop( e ) || isSwitch( e ) || dynamic_cast< CompoundStmt *>( e.get_controlStructure() ); }
+		bool isContinueTarget( const MLEMutator::Entry & e ) { return isLoop( e ); }
+		bool isFallthroughTarget( const MLEMutator::Entry & e ) { return dynamic_cast< CaseStmt *>( e.get_controlStructure() );; }
+		bool isFallthroughDefaultTarget( const MLEMutator::Entry & e ) { return isSwitch( e ); }
+	} // namespace
 
 	// break labels have to come after the statement they break out of, so mutate a statement, then if they inform us
 	// through the breakLabel field tha they need a place to jump to on a break statement, add the break label to the
 	// body of statements
-	void MLEMutator::fixBlock( std::list< Statement * > &kids ) {
+	void MLEMutator::fixBlock( std::list< Statement * > &kids, bool caseClause ) {
+		SemanticErrorException errors;
+
 		for ( std::list< Statement * >::iterator k = kids.begin(); k != kids.end(); k++ ) {
-			*k = (*k)->acceptMutator(*visitor);
+			if ( caseClause ) {
+				// once a label is seen, it's no longer a valid fallthrough target
+				for ( Label & l : (*k)->labels ) {
+					fallthroughLabels.erase( l );
+				}
+			}
+
+			// aggregate errors since the PassVisitor mutate loop was unrollled
+			try {
+				*k = (*k)->acceptMutator(*visitor);
+			} catch( SemanticErrorException &e ) {
+				errors.append( e );
+			}
 
 			if ( ! get_breakLabel().empty() ) {
@@ -55,4 +75,8 @@
 			} // if
 		} // for
+
+		if ( ! errors.isEmpty() ) {
+			throw errors;
+		}
 	}
 
@@ -63,4 +87,5 @@
 			Label brkLabel = generator->newLabel("blockBreak", cmpndStmt);
 			enclosingControlStructures.push_back( Entry( cmpndStmt, brkLabel ) );
+			GuardAction( [this]() { enclosingControlStructures.pop_back(); } );
 		} // if
 
@@ -74,5 +99,4 @@
 				set_breakLabel( enclosingControlStructures.back().useBreakExit() );
 			} // if
-			enclosingControlStructures.pop_back();
 		} // if
 	}
@@ -112,9 +136,9 @@
 					if ( isContinue ) {
 						// continue target is outermost loop
-						targetEntry = std::find_if( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), [](Entry &e) { return isLoop( e.get_controlStructure() ); } );
+						targetEntry = std::find_if( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), isContinueTarget );
 					} else {
-						// break target is outmost control structure
-						if ( enclosingControlStructures.empty() ) SemanticError( branchStmt->location, "'break' outside a loop, switch, or labelled block" );
-						targetEntry = enclosingControlStructures.rbegin();
+						// break target is outermost loop, switch, or block control structure
+						if ( enclosingControlStructures.empty() ) SemanticError( branchStmt->location, "'break' outside a loop, 'switch', or labelled block" );
+						targetEntry = std::find_if( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), isBreakTarget );
 					} // if
 				} else {
@@ -123,9 +147,48 @@
 				} // if
 				// ensure that selected target is valid
-				if ( targetEntry == enclosingControlStructures.rend() || (isContinue && ! isLoop( targetEntry->get_controlStructure() ) ) ) {
+				if ( targetEntry == enclosingControlStructures.rend() || (isContinue && ! isContinueTarget( *targetEntry ) ) ) {
 					SemanticError( branchStmt->location, toString( (isContinue ? "'continue'" : "'break'"), " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "), originalTarget ) );
 				} // if
 				break;
 			}
+			case BranchStmt::FallThrough:
+				targetEntry = std::find_if( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), isFallthroughTarget );
+				// ensure that selected target is valid
+				if ( targetEntry == enclosingControlStructures.rend() ) {
+					SemanticError( branchStmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
+				} // if
+				if ( branchStmt->get_target() != "" ) {
+					// labelled fallthrough
+					// target must be in the set of valid fallthrough labels
+					if ( ! fallthroughLabels.count( branchStmt->get_target() ) ) {
+						SemanticError( branchStmt->location, toString( "'fallthrough' target must be a later case statement: ", originalTarget ) );
+					}
+					return new BranchStmt( originalTarget, BranchStmt::Goto );
+				}
+				break;
+			case BranchStmt::FallThroughDefault: {
+				// fallthrough default
+				targetEntry = std::find_if( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), isFallthroughDefaultTarget );
+
+				// ensure that fallthrough is within a switch or choose
+				if ( targetEntry == enclosingControlStructures.rend() ) {
+					SemanticError( branchStmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
+				} // if
+
+				// ensure that switch or choose has a default clause
+				SwitchStmt * switchStmt = strict_dynamic_cast< SwitchStmt * >( targetEntry->get_controlStructure() );
+				bool foundDefault = false;
+				for ( Statement * stmt : switchStmt->statements ) {
+					CaseStmt * caseStmt = strict_dynamic_cast< CaseStmt * >( stmt );
+					if ( caseStmt->isDefault() ) {
+						foundDefault = true;
+					} // if
+				} // for
+				if ( ! foundDefault ) {
+					SemanticError( branchStmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose' control structure with a 'default' clause" );
+				}
+				break;
+			}
+
 			default:
 				assert( false );
@@ -142,4 +205,16 @@
 				assert( targetEntry->useContExit() != "");
 				exitLabel = targetEntry->useContExit();
+				break;
+		  case BranchStmt::FallThrough:
+				assert( targetEntry->useFallExit() != "");
+				exitLabel = targetEntry->useFallExit();
+				break;
+		  case BranchStmt::FallThroughDefault:
+				assert( targetEntry->useFallDefaultExit() != "");
+				exitLabel = targetEntry->useFallDefaultExit();
+				// check that fallthrough default comes before the default clause
+				if ( ! targetEntry->isFallDefaultValid() ) {
+					SemanticError( branchStmt->location, "'fallthrough default' must precede the 'default' clause" );
+				}
 				break;
 		  default:
@@ -187,4 +262,5 @@
 		Label contLabel = generator->newLabel("loopContinue", loopStmt);
 		enclosingControlStructures.push_back( Entry( loopStmt, brkLabel, contLabel ) );
+		GuardAction( [this]() { enclosingControlStructures.pop_back(); } );
 	}
 
@@ -197,6 +273,5 @@
 
 		// this will take the necessary steps to add definitions of the previous two labels, if they are used.
-		loopStmt->set_body( mutateLoop( loopStmt->get_body(), e ) );
-		enclosingControlStructures.pop_back();
+		loopStmt->body = mutateLoop( loopStmt->get_body(), e );
 		return loopStmt;
 	}
@@ -224,4 +299,5 @@
 			Label brkLabel = generator->newLabel("blockBreak", ifStmt);
 			enclosingControlStructures.push_back( Entry( ifStmt, brkLabel ) );
+			GuardAction( [this]() { enclosingControlStructures.pop_back(); } );
 		} // if
 	}
@@ -233,5 +309,4 @@
 				set_breakLabel( enclosingControlStructures.back().useBreakExit() );
 			} // if
-			enclosingControlStructures.pop_back();
 		} // if
 		return ifStmt;
@@ -240,6 +315,39 @@
 	void MLEMutator::premutate( CaseStmt *caseStmt ) {
 		visit_children = false;
+
+		// mark default as seen before visiting its statements to catch default loops
+		if ( caseStmt->isDefault() ) {
+			enclosingControlStructures.back().seenDefault();
+		} // if
+
 		caseStmt->condition = maybeMutate( caseStmt->condition, *visitor );
-		fixBlock( caseStmt->stmts );
+		Label fallLabel = generator->newLabel( "fallThrough", caseStmt );
+		{
+			// ensure that stack isn't corrupted by exceptions in fixBlock
+			auto guard = makeFuncGuard( [&]() { enclosingControlStructures.push_back( Entry( caseStmt, fallLabel ) ); }, [this]() { enclosingControlStructures.pop_back(); } );
+
+			// empty case statement
+			if( ! caseStmt->stmts.empty() ) {
+				// the parser ensures that all statements in a case are grouped into a block
+				CompoundStmt * block = strict_dynamic_cast< CompoundStmt * >( caseStmt->stmts.front() );
+				fixBlock( block->kids, true );
+
+				// add fallthrough label if necessary
+				assert( ! enclosingControlStructures.empty() );
+				if ( enclosingControlStructures.back().isFallUsed() ) {
+					std::list<Label> ls{ enclosingControlStructures.back().useFallExit() };
+					caseStmt->stmts.push_back( new NullStmt( ls ) );
+				} // if
+			} // if
+		}
+		assert( ! enclosingControlStructures.empty() );
+		assertf( dynamic_cast<SwitchStmt *>( enclosingControlStructures.back().get_controlStructure() ), "Control structure enclosing a case clause must be a switch, but is: %s", toCString( enclosingControlStructures.back().get_controlStructure() ) );
+		if ( caseStmt->isDefault() ) {
+			if ( enclosingControlStructures.back().isFallDefaultUsed() ) {
+				// add fallthrough default label if necessary
+				std::list<Label> ls{ enclosingControlStructures.back().useFallDefaultExit() };
+				caseStmt->stmts.push_front( new NullStmt( ls ) );
+			} // if
+		} // if
 	}
 
@@ -247,5 +355,25 @@
 		// generate a label for breaking out of a labeled switch
 		Label brkLabel = generator->newLabel("switchBreak", switchStmt);
-		enclosingControlStructures.push_back( Entry(switchStmt, brkLabel) );
+		auto it = std::find_if( switchStmt->statements.rbegin(), switchStmt->statements.rend(), [](Statement * stmt) {
+			CaseStmt * caseStmt = strict_dynamic_cast< CaseStmt * >( stmt );
+			return caseStmt->isDefault();
+		});
+		CaseStmt * defaultCase = it != switchStmt->statements.rend() ? strict_dynamic_cast<CaseStmt *>( *it ) : nullptr;
+		Label fallDefaultLabel = defaultCase ? generator->newLabel( "fallThroughDefault", defaultCase ) : "";
+		enclosingControlStructures.push_back( Entry(switchStmt, brkLabel, fallDefaultLabel) );
+		GuardAction( [this]() { enclosingControlStructures.pop_back(); } );
+
+		// Collect valid labels for fallthrough. This is initially all labels at the same level as a case statement.
+		// As labels are seen during traversal, they are removed, since fallthrough is not allowed to jump backwards.
+		for ( Statement * stmt : switchStmt->statements ) {
+			CaseStmt * caseStmt = strict_dynamic_cast< CaseStmt * >( stmt );
+			if ( caseStmt->stmts.empty() ) continue;
+			CompoundStmt * block = dynamic_cast< CompoundStmt * >( caseStmt->stmts.front() );
+			for ( Statement * stmt : block->kids ) {
+				for ( Label & l : stmt->labels ) {
+					fallthroughLabels.insert( l );
+				}
+			}
+		}
 	}
 
@@ -272,5 +400,4 @@
 
 		assert ( enclosingControlStructures.back() == switchStmt );
-		enclosingControlStructures.pop_back();
 		return switchStmt;
 	}
