Index: src/Common/CodeLocation.hpp
===================================================================
--- src/Common/CodeLocation.hpp	(revision 3c55fcdbcd55d1744f1b2f592b1b158517e23781)
+++ src/Common/CodeLocation.hpp	(revision 4558df29929781e8d911ce6cdc5f0dfac9ef0d8b)
@@ -17,9 +17,9 @@
 
 #include <iostream>
-#include <string>
+#include "Symbol.hpp"
 
 struct CodeLocation {
 	int first_line = -1, first_column = -1, last_line = -1, last_column = -1;
-	std::string filename = "";
+	Symbol filename = "";
 
 	/// Create a new unset CodeLocation.
@@ -46,6 +46,6 @@
 
 	bool startsBefore( CodeLocation const & other ) const {
-		if( filename < other.filename ) return true;
-		if( filename > other.filename ) return false;
+		if( filename.str() < other.filename.str() ) return true;
+		if( filename.str() > other.filename.str() ) return false;
 
 		if( first_line < other.first_line ) return true;
@@ -72,4 +72,4 @@
 inline std::ostream & operator<<( std::ostream & out, const CodeLocation & location ) {
 	// Column number ":1" allows IDEs to parse the error message and position the cursor in the source text.
-	return location.isSet() ? out << location.filename << ":" << location.first_line << ":1 " : out;
+	return location.isSet() ? out << location.filename.str() << ":" << location.first_line << ":1 " : out;
 }
Index: src/Common/Symbol.cpp
===================================================================
--- src/Common/Symbol.cpp	(revision 4558df29929781e8d911ce6cdc5f0dfac9ef0d8b)
+++ src/Common/Symbol.cpp	(revision 4558df29929781e8d911ce6cdc5f0dfac9ef0d8b)
@@ -0,0 +1,148 @@
+#include "Symbol.hpp"
+
+#include <unordered_map>
+
+// This class (and the member-like helpers) are the implementation details
+// of the Symbol class. It is just does reference counting to share strings.
+// It is designed for maintainablity, but also to optimize the copy cases.
+class SymbolData {
+public:
+	std::string const value;
+	// As long as we are using a pointer sized counter,
+	// overflow should never be an issue.
+	std::size_t refCount;
+
+	SymbolData(std::string const & value, std::size_t refCount) :
+		value(value), refCount(refCount)
+	{}
+};
+
+namespace {
+	template<typename T>
+	struct IndirectHash {
+		std::hash<T> hasher;
+		std::size_t operator()(T const * const & val) const {
+			return hasher(*val);
+		}
+	};
+
+	template<typename T>
+	struct IndirectEqualTo {
+		std::equal_to<T> equals;
+		bool operator()(T const * const & lhs, T const * const & rhs) const {
+			return equals(*lhs, *rhs);
+		}
+	};
+} // namespace
+
+using SymbolMap = std::unordered_map<std::string const *, SymbolData *,
+	IndirectHash<std::string>, IndirectEqualTo<std::string>>;
+
+/// Get the storage for the map of symbol data.
+// Note: This is basically static memory, but wrapping the data in a function
+// causes the constructor to run with the proper timing.
+static SymbolMap & getAllSymbols() {
+	static SymbolMap allSymbols;
+	return allSymbols;
+}
+
+/// Clear out all unsed SymbolData.
+static void eraseUnused() {
+	SymbolMap & allSymbols = getAllSymbols();
+
+	auto it = allSymbols.begin();
+	while (it != allSymbols.end()) {
+		if (it->second->refCount) {
+			++it;
+		} else {
+			delete it->second;
+			it = allSymbols.erase(it);
+		}
+	}
+}
+
+/// Convert a string to a new or existing SymbolData.
+static SymbolData * getSymbolData(std::string const & str) {
+	SymbolMap & allSymbols = getAllSymbols();
+
+	// If there is an existing symbol, re-use it.
+	auto it = allSymbols.find(&str);
+	if (it != allSymbols.end()) {
+		SymbolData * data = it->second;
+		++data->refCount;
+		return data;
+	}
+
+	// If these is no existing symbol, create the required data.
+	SymbolData * data = new SymbolData(str, 1);
+	allSymbols.insert(std::make_pair(&data->value, data));
+	return data;
+}
+
+/// Reduce reference count and free the SymbolData as needed.
+static void decSymbolData(SymbolData * data) {
+	// First comes the actual decrement.
+	--data->refCount;
+
+	// If it has hit zero, remove it from the map.
+	if (0 == data->refCount) {
+		eraseUnused();
+	}
+}
+
+Symbol::Symbol() : data(getSymbolData(std::string())) {}
+
+Symbol::Symbol(std::string const & str) : data(getSymbolData(str)) {}
+
+Symbol::Symbol(char const * str) : data(getSymbolData(str)) {}
+
+Symbol::Symbol(Symbol const & other) : data(other.data) {
+	++data->refCount;
+}
+
+Symbol::Symbol(Symbol && other) : data(other.data) {
+	++data->refCount;
+}
+
+Symbol::~Symbol() {
+	decSymbolData(data);
+}
+
+Symbol & Symbol::operator=(std::string const & str) {
+	SymbolData * dat = getSymbolData(str);
+	decSymbolData(data);
+	data = dat;
+	return *this;
+}
+
+Symbol & Symbol::operator=(char const * str) {
+	return this->operator=(std::string(str));
+}
+
+Symbol & Symbol::operator=(Symbol const & other) {
+	++other.data->refCount;
+	decSymbolData(data);
+	data = other.data;
+	return *this;
+}
+
+Symbol & Symbol::operator=(Symbol && other) {
+	Symbol const & ref = other;
+	return this->operator=(ref);
+}
+
+bool Symbol::operator==(Symbol const & other) const {
+	return data == other.data;
+}
+
+bool Symbol::operator!=(Symbol const & other) const {
+	return data != other.data;
+}
+
+std::string const & Symbol::str() const {
+	return data->value;
+}
+
+char const * Symbol::c_str() const {
+	return data->value.c_str();
+}
Index: src/Common/Symbol.hpp
===================================================================
--- src/Common/Symbol.hpp	(revision 4558df29929781e8d911ce6cdc5f0dfac9ef0d8b)
+++ src/Common/Symbol.hpp	(revision 4558df29929781e8d911ce6cdc5f0dfac9ef0d8b)
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <string>
+
+// Internal Type:
+class SymbolData;
+
+/// A Symbol is an interned string, where the characters are 'hidden'.
+class Symbol final {
+	SymbolData * data;
+public:
+	/// Create a Symbol for the empty string.
+	Symbol();
+
+	Symbol(std::string const &);
+	Symbol(char const *);
+	Symbol(Symbol const &);
+	Symbol(Symbol &&);
+
+	~Symbol();
+
+	Symbol & operator=(std::string const &);
+	Symbol & operator=(char const *);
+	Symbol & operator=(Symbol const &);
+	Symbol & operator=(Symbol &&);
+
+	bool operator==(Symbol const &) const;
+	bool operator!=(Symbol const &) const;
+
+	std::string const & str() const;
+	char const * c_str() const;
+};
Index: src/Common/module.mk
===================================================================
--- src/Common/module.mk	(revision 3c55fcdbcd55d1744f1b2f592b1b158517e23781)
+++ src/Common/module.mk	(revision 4558df29929781e8d911ce6cdc5f0dfac9ef0d8b)
@@ -48,4 +48,6 @@
 	Common/Stats/Time.cpp \
 	Common/Stats/Time.hpp \
+	Common/Symbol.cpp \
+	Common/Symbol.hpp \
 	Common/ToString.hpp \
 	Common/UniqueName.cpp \
