Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 4b1be68be8224f2e1d526978d996416c7cc19918)
+++ src/SymTab/Autogen.cc	(revision e2c70abaacda28a5de17564ffc349fdaeb8b9ab3)
@@ -331,5 +331,5 @@
 			definitions.push_back( dcl );
 			indexer.addId( dcl );
-		} catch ( SemanticError err ) {
+		} catch ( SemanticErrorException err ) {
 			// okay if decl does not resolve - that means the function should not be generated
 			delete dcl;
Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision 4b1be68be8224f2e1d526978d996416c7cc19918)
+++ src/SymTab/Indexer.cc	(revision e2c70abaacda28a5de17564ffc349fdaeb8b9ab3)
@@ -443,10 +443,10 @@
 			// isomorphic to C type-compatibility, which it may not be.
 			if ( hasIncompatibleCDecl( name, mangleName, scope ) ) {
-				throw SemanticError( decl, "conflicting overload of C function " );
+				SemanticError( decl, "conflicting overload of C function " );
 			}
 		} else {
 			// Check that a Cforall declaration doesn't override any C declaration
 			if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
-				throw SemanticError( decl, "Cforall declaration hides C function " );
+				SemanticError( decl, "Cforall declaration hides C function " );
 			}
 		}
@@ -463,10 +463,10 @@
 	void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
 		// default handling of conflicts is to raise an error
-		addId( decl, [decl](IdData &, const std::string & msg) { throw SemanticError( decl, msg ); return true; }, baseExpr );
+		addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr );
 	}
 
 	void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
 		// default handling of conflicts is to raise an error
-		addId( decl, [decl](IdData &, const std::string & msg) { throw SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
+		addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
 	}
 
@@ -477,5 +477,5 @@
 			return true;
 		} else {
-			throw SemanticError( added, "redeclaration of " );
+			SemanticError( added, "redeclaration of " );
 		}
 	}
@@ -504,5 +504,5 @@
 			return false;
 		} else if ( ! added->get_members().empty() ) {
-			throw SemanticError( added, "redeclaration of " );
+			SemanticError( added, "redeclaration of " );
 		} // if
 		return true;
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 4b1be68be8224f2e1d526978d996416c7cc19918)
+++ src/SymTab/Validate.cc	(revision e2c70abaacda28a5de17564ffc349fdaeb8b9ab3)
@@ -360,5 +360,5 @@
 			// the only case in which "void" is valid is where it is the only one in the list
 			if ( containsVoid && ( nvals > 1 || isVarArgs ) ) {
-				throw SemanticError( func, "invalid type void in function type " );
+				SemanticError( func, "invalid type void in function type " );
 			}
 
@@ -401,5 +401,5 @@
 		for ( Expression * param : inst->parameters ) {
 			if ( ! dynamic_cast< TypeExpr * >( param ) ) {
-				throw SemanticError( inst, "Expression parameters for generic types are currently unsupported: " );
+				SemanticError( inst, "Expression parameters for generic types are currently unsupported: " );
 			}
 		}
@@ -501,8 +501,8 @@
 		TraitDecl *traitDecl = local_indexer->lookupTrait( traitInst->name );
 		if ( ! traitDecl ) {
-			throw SemanticError( traitInst->location, "use of undeclared trait " + traitInst->name );
+			SemanticError( traitInst->location, "use of undeclared trait " + traitInst->name );
 		} // if
 		if ( traitDecl->get_parameters().size() != traitInst->get_parameters().size() ) {
-			throw SemanticError( traitInst, "incorrect number of trait parameters: " );
+			SemanticError( traitInst, "incorrect number of trait parameters: " );
 		} // if
 		traitInst->baseTrait = traitDecl;
@@ -512,5 +512,5 @@
 			TypeExpr * expr = dynamic_cast< TypeExpr * >( std::get<1>(p) );
 			if ( ! expr ) {
-				throw SemanticError( std::get<1>(p), "Expression parameters for trait instances are currently unsupported: " );
+				SemanticError( std::get<1>(p), "Expression parameters for trait instances are currently unsupported: " );
 			}
 			if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( expr->get_type() ) ) {
@@ -618,5 +618,5 @@
 				bool isVoid = fixFunction( assertion );
 				if ( isVoid ) {
-					throw SemanticError( node, "invalid type void in assertion of function " );
+					SemanticError( node, "invalid type void in assertion of function " );
 				} // if
 			} // for
@@ -662,5 +662,5 @@
 		// were cast to void.
 		if ( ! returnStmt->get_expr() && returnVals.size() != 0 ) {
-			throw SemanticError( returnStmt, "Non-void function returns no values: " );
+			SemanticError( returnStmt, "Non-void function returns no values: " );
 		}
 	}
@@ -703,5 +703,5 @@
 				ReferenceToType *rtt = dynamic_cast<ReferenceToType*>(ret);
 				if ( ! rtt ) {
-					throw SemanticError( typeInst->location, "Cannot apply type parameters to base type of " + typeInst->name );
+					SemanticError( typeInst->location, "Cannot apply type parameters to base type of " + typeInst->name );
 				}
 				rtt->get_parameters().clear();
@@ -741,5 +741,5 @@
 			Type * t2 = typedefNames[ tyDecl->get_name() ].first->get_base();
 			if ( ! ResolvExpr::typesCompatible( t1, t2, Indexer() ) ) {
-				throw SemanticError( tyDecl->location, "Cannot redefine typedef: " + tyDecl->name );
+				SemanticError( tyDecl->location, "Cannot redefine typedef: " + tyDecl->name );
 			}
 			// Cannot redefine VLA typedefs. Note: this is slightly incorrect, because our notion of VLAs
@@ -748,5 +748,5 @@
 			// to fix this corner case likely outweighs the utility of allowing it.
 			if ( isVariableLength( t1 ) || isVariableLength( t2 ) ) {
-				throw SemanticError( tyDecl->location, "Cannot redefine typedef: " + tyDecl->name );
+				SemanticError( tyDecl->location, "Cannot redefine typedef: " + tyDecl->name );
 			}
 		} else {
@@ -897,12 +897,12 @@
 		if ( CodeGen::isCtorDtorAssign( funcDecl->get_name() ) ) { // TODO: also check /=, etc.
 			if ( params.size() == 0 ) {
-				throw SemanticError( funcDecl, "Constructors, destructors, and assignment functions require at least one parameter " );
+				SemanticError( funcDecl, "Constructors, destructors, and assignment functions require at least one parameter " );
 			}
 			ReferenceType * refType = dynamic_cast< ReferenceType * >( params.front()->get_type() );
 			if ( ! refType ) {
-				throw SemanticError( funcDecl, "First parameter of a constructor, destructor, or assignment function must be a reference " );
+				SemanticError( funcDecl, "First parameter of a constructor, destructor, or assignment function must be a reference " );
 			}
 			if ( CodeGen::isCtorDtor( funcDecl->get_name() ) && returnVals.size() != 0 ) {
-				throw SemanticError( funcDecl, "Constructors and destructors cannot have explicit return values " );
+				SemanticError( funcDecl, "Constructors and destructors cannot have explicit return values " );
 			}
 		}
@@ -939,6 +939,6 @@
 
 			sub.apply( inst );
-			if ( args.size() < params->size() ) throw SemanticError( inst, "Too few type arguments in generic type " );
-			if ( args.size() > params->size() ) throw SemanticError( inst, "Too many type arguments in generic type " );
+			if ( args.size() < params->size() ) SemanticError( inst, "Too few type arguments in generic type " );
+			if ( args.size() > params->size() ) SemanticError( inst, "Too many type arguments in generic type " );
 		}
 	}
