Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 834b89258d7f4a00204b5a1203c6de5a5161498f)
+++ src/Common/PassVisitor.impl.h	(revision d55d7a68246b165aeaa9e161109032ddd07146d8)
@@ -77,5 +77,4 @@
 			maybeAccept_impl( *i, visitor );
 		} catch( SemanticError &e ) {
-			e.set_location( (*i)->location );
 			errors.append( e );
 		}
@@ -104,5 +103,4 @@
 			maybeMutate_impl( *i, mutator );
 		} catch( SemanticError &e ) {
-			e.set_location( (*i)->location );
 			errors.append( e );
 		}
@@ -134,5 +132,4 @@
 			}
 		} catch( SemanticError &e ) {
-			e.set_location( (*i)->location );
 			errors.append( e );
 		}
@@ -163,5 +160,4 @@
 			} // if
 		} catch( SemanticError &e ) {
-			e.set_location( (*i)->location );
 			errors.append( e );
 		} // try
@@ -200,5 +196,4 @@
 
 		} catch ( SemanticError &e ) {
-			e.set_location( (*i)->location );
 			errors.append( e );
 		}
Index: src/Common/SemanticError.cc
===================================================================
--- src/Common/SemanticError.cc	(revision 834b89258d7f4a00204b5a1203c6de5a5161498f)
+++ src/Common/SemanticError.cc	(revision d55d7a68246b165aeaa9e161109032ddd07146d8)
@@ -23,9 +23,6 @@
 #include "SemanticError.h"
 
-SemanticError::SemanticError() {
-}
-
-SemanticError::SemanticError( std::string error ) {
-	append( error );
+SemanticError::SemanticError( CodeLocation location, std::string error ) {
+	append( location, error );
 }
 
@@ -34,6 +31,6 @@
 }
 
-void SemanticError::append( const std::string & msg ) {
-	errors.emplace_back( error_str() + msg );
+void SemanticError::append( CodeLocation location, const std::string & msg ) {
+	errors.emplace_back( location, msg );
 }
 
@@ -42,13 +39,13 @@
 }
 
-void SemanticError::print( std::ostream &os ) {
+void SemanticError::print() {
 	using std::to_string;
 	for( auto err : errors ) {
-		os << err.location << err.description << std::endl;
+		std::cerr << bold() << err.location << error_str() << reset_font() << err.description << std::endl;
 	}
 }
 
-void SemanticError::set_location( const CodeLocation& location ) {
-	errors.begin()->maybeSet( location );
+SemanticWarning::SemanticWarning( CodeLocation location, std::string msg ) {
+	std::cerr << bold() << location << warning_str() << reset_font() << msg << std::endl;
 }
 
Index: src/Common/SemanticError.h
===================================================================
--- src/Common/SemanticError.h	(revision 834b89258d7f4a00204b5a1203c6de5a5161498f)
+++ src/Common/SemanticError.h	(revision d55d7a68246b165aeaa9e161109032ddd07146d8)
@@ -24,24 +24,23 @@
 #include "CodeLocation.h"								// for CodeLocation, toString
 
+//-----------------------------------------------------------------------------
+// Errors
 struct error {
+	CodeLocation location;
 	std::string description;
-	CodeLocation location;
 
 	error() = default;
-	error( const std::string & str ) : description( str ) {}
-
-	void maybeSet( const CodeLocation & location ) {
-		if( this->location.isUnset() ) {
-			this->location = location;
-		}
-	}
+	error( CodeLocation loc, const std::string & str ) : location( loc ), description( str ) {}
 };
 
 class SemanticError : public std::exception {
   public:
-	SemanticError();
-	SemanticError( std::string error );
-	template< typename T > SemanticError( const std::string & error, const T * obj );
+  	SemanticError() = default;
+	SemanticError( CodeLocation location, std::string error );
 	~SemanticError() throw() {}
+
+	// constructs an exception using the given message and the printed representation of the obj (T must have a print method)
+	template< typename T > SemanticError(const T * obj, const std::string & error);
+	template< typename T > SemanticError( CodeLocation location, const T * obj, const std::string & error);
 
 	static inline const std::string & error_str() {
@@ -51,11 +50,7 @@
 
 	void append( SemanticError & other );
-	void append( const std::string & );
+	void append( CodeLocation location, const std::string & );
 	bool isEmpty() const;
-	void print( std::ostream & os );
-
-	void set_location( const CodeLocation & location );
-	// constructs an exception using the given message and the printed representation of the obj (T must have a print
-	// method)
+	void print();
   private:
 	std::list< error > errors;
@@ -63,6 +58,68 @@
 
 template< typename T >
-SemanticError::SemanticError( const std::string & error, const T * obj ) {
-	append( toString( error, obj ) );
+SemanticError::SemanticError( const T * obj, const std::string & error )
+	: SemanticError( obj->location, toString( error, obj ) )
+{}
+
+template< typename T >
+SemanticError::SemanticError( CodeLocation location, const T * obj, const std::string & error )
+	: SemanticError( location, toString( error, obj ) )
+{}
+
+//-----------------------------------------------------------------------------
+// Warnings
+class SemanticWarning {
+  public:
+  	SemanticWarning( CodeLocation location, std::string error );
+	~SemanticWarning() throw() {}
+
+	// constructs an exception using the given message and the printed representation of the obj (T must have a print method)
+	template< typename T > SemanticWarning(const T * obj, const std::string & error);
+	template< typename T > SemanticWarning( CodeLocation location, const T * obj, const std::string & error);
+
+	static inline const std::string & warning_str() {
+		static std::string str = isatty( STDERR_FILENO ) ? "\e[95mwarning:\e[39m " : "warning: ";
+		return str;
+	}
+
+  private:
+};
+
+template< typename T >
+SemanticWarning::SemanticWarning( const T * obj, const std::string & error )
+	: SemanticWarning( obj->location, toString( error, obj ) )
+{}
+
+template< typename T >
+SemanticWarning::SemanticWarning( CodeLocation location, const T * obj, const std::string & error )
+	: SemanticWarning( location, toString( error, obj ) )
+{}
+
+//-----------------------------------------------------------------------------
+// Helpers
+static inline const std::string & bold_ttycode() {
+	static std::string str = isatty( STDERR_FILENO ) ? "\e[1m" : "";
+	return str;
+}
+
+static inline const std::string & reset_font_ttycode() {
+	static std::string str = isatty( STDERR_FILENO ) ? "\e[0m" : "";
+	return str;
+}
+
+static inline std::string make_bold( const std::string & str ) {
+	return bold_ttycode() + str + reset_font_ttycode();
+}
+
+struct bold {};
+static inline std::ostream & operator<<(std::ostream & os, bold) {
+	os << bold_ttycode();
+	return os;
+}
+
+struct reset_font {};
+static inline std::ostream & operator<<(std::ostream & os, reset_font) {
+	os << reset_font_ttycode();
+	return os;
 }
 
