diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index 80b94be4c53..f1bd93a4a5d 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -106,6 +106,10 @@ fn compile_input(session::session sess, ast::crate_cfg cfg, str input,
     if (sess.get_opts().output_type == link::output_type_none) { ret; }
     crate = time(time_passes, "configuration",
                  bind front::config::strip_unconfigured_items(crate));
+    if (sess.get_opts().test) {
+        crate = time(time_passes, "building test harness",
+                     bind front::test::modify_for_testing(sess, crate));
+    }
     auto ast_map = time(time_passes, "ast indexing",
                         bind middle::ast_map::map_crate(*crate));
     auto d =
@@ -229,7 +233,8 @@ options:
     --time-passes      time the individual phases of the compiler
     --time-llvm-passes time the individual phases of the LLVM backend
     --sysroot <path>   override the system root (default: rustc's directory)
-    --no-typestate     don't run the typestate pass (unsafe!)\n\n");
+    --no-typestate     don't run the typestate pass (unsafe!)
+    --test             build test harness\n\n");
 }
 
 fn get_os(str triple) -> session::os {
@@ -324,6 +329,7 @@ fn build_session_options(str binary, getopts::match match, str binary_dir) ->
             case (some(?s)) { s }
         };
     auto cfg = parse_cfgspecs(getopts::opt_strs(match, "cfg"));
+    auto test = opt_present(match, "test");
     let @session::options sopts =
         @rec(shared=shared,
              optimize=opt_level,
@@ -337,7 +343,8 @@ fn build_session_options(str binary, getopts::match match, str binary_dir) ->
              output_type=output_type,
              library_search_paths=library_search_paths,
              sysroot=sysroot,
-             cfg=cfg);
+             cfg=cfg,
+             test=test);
     ret sopts;
 }
 
@@ -367,7 +374,7 @@ fn main(vec[str] args) {
          optflag("c"), optopt("o"), optflag("g"), optflag("save-temps"),
          optopt("sysroot"), optflag("stats"), optflag("time-passes"),
          optflag("time-llvm-passes"), optflag("no-typestate"),
-         optflag("noverify"), optmulti("cfg")];
+         optflag("noverify"), optmulti("cfg"), optflag("test")];
     auto binary = vec::shift[str](args);
     auto binary_dir = fs::dirname(binary);
     auto match =
diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs
index 3dc947477b8..7dce5b9b068 100644
--- a/src/comp/driver/session.rs
+++ b/src/comp/driver/session.rs
@@ -37,7 +37,8 @@ type options =
         str sysroot,
         // The crate config requested for the session, which may be combined
         // with additional crate configurations during the compile process
-        ast::crate_cfg cfg);
+        ast::crate_cfg cfg,
+        bool test);
 
 type crate_metadata = rec(str name, vec[u8] data);
 
diff --git a/src/comp/front/test.rs b/src/comp/front/test.rs
new file mode 100644
index 00000000000..376efc7932e
--- /dev/null
+++ b/src/comp/front/test.rs
@@ -0,0 +1,44 @@
+import driver::session;
+import syntax::ast;
+import syntax::fold;
+
+export modify_for_testing;
+
+type test_ctxt = rec(@session::session sess);
+
+// Traverse the crate, collecting all the test functions, eliding any
+// existing main functions, and synthesizing a main test harness
+fn modify_for_testing(&session::session sess,
+                      @ast::crate crate) -> @ast::crate {
+
+  auto cx = rec(sess = @sess);
+
+  auto precursor = rec(fold_crate = bind fold_crate(cx, _, _)
+                       with *fold::default_ast_fold());
+
+  auto fold = fold::make_fold(precursor);
+  auto res = @fold.fold_crate(*crate);
+  // FIXME: This is necessary to break a circular reference
+  fold::dummy_out(fold);
+  ret res;
+}
+
+fn fold_crate(&test_ctxt cx, &ast::crate_ c,
+              fold::ast_fold fld) -> ast::crate_ {
+  auto folded = fold::noop_fold_crate(c, fld);
+  ret rec(module = add_test_module(folded.module)
+          with folded);
+}
+
+fn add_test_module(&ast::_mod m) -> ast::_mod {
+  ret m;
+}
+
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index fe97761cf8c..69336c5cb61 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -66,6 +66,7 @@ mod syntax {
 mod front {
     mod attr;
     mod config;
+    mod test;
 }
 
 mod back {
diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs
index 64c28ad829a..c53665cf71c 100644
--- a/src/comp/syntax/fold.rs
+++ b/src/comp/syntax/fold.rs
@@ -10,6 +10,7 @@ export ast_fold;
 export default_ast_fold;
 export make_fold;
 export dummy_out;
+export noop_fold_crate;
 
 type ast_fold = @mutable a_f;