about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-08-24 15:28:43 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-08-24 15:51:16 -0700
commitc284b8b1dc348ab8b9c82350dd1b4e53fac1225c (patch)
tree99de39b149969275f6f9ddebd7a9f555d91c5bff
parenta8f1bee4574b8427a052e2fad93a90839288584b (diff)
downloadrust-c284b8b1dc348ab8b9c82350dd1b4e53fac1225c.tar.gz
rust-c284b8b1dc348ab8b9c82350dd1b4e53fac1225c.zip
Start using core::path2::Path in a lot of places.
-rw-r--r--src/cargo/cargo.rs477
-rw-r--r--src/cargo/pgp.rs29
-rw-r--r--src/compiletest/common.rs10
-rw-r--r--src/compiletest/compiletest.rs48
-rw-r--r--src/compiletest/errors.rs2
-rw-r--r--src/compiletest/header.rs14
-rw-r--r--src/compiletest/runtest.rs132
-rw-r--r--src/fuzzer/fuzzer.rs103
-rw-r--r--src/libcore/core.rc2
-rw-r--r--src/libcore/core.rs10
-rw-r--r--src/libcore/io.rs45
-rw-r--r--src/libcore/os.rs248
-rw-r--r--src/libcore/path2.rs294
-rw-r--r--src/libstd/tempfile.rs15
-rw-r--r--src/libstd/test.rs2
-rw-r--r--src/libsyntax/ext/source_util.rs17
-rw-r--r--src/libsyntax/parse.rs25
-rw-r--r--src/libsyntax/parse/eval.rs55
-rw-r--r--src/rustc/back/link.rs129
-rw-r--r--src/rustc/back/rpath.rs255
-rw-r--r--src/rustc/driver/driver.rs65
-rw-r--r--src/rustc/driver/rustc.rs8
-rw-r--r--src/rustc/driver/session.rs6
-rw-r--r--src/rustc/metadata/creader.rs4
-rw-r--r--src/rustc/metadata/cstore.rs10
-rw-r--r--src/rustc/metadata/filesearch.rs83
-rw-r--r--src/rustc/metadata/loader.rs32
-rw-r--r--src/rustc/middle/trans/base.rs2
-rw-r--r--src/rustc/middle/trans/debuginfo.rs13
-rw-r--r--src/rustc/util/ppaux.rs3
-rw-r--r--src/rustdoc/astsrv.rs2
-rw-r--r--src/rustdoc/config.rs27
-rw-r--r--src/rustdoc/markdown_index_pass.rs4
-rw-r--r--src/rustdoc/markdown_pass.rs2
-rw-r--r--src/rustdoc/markdown_writer.rs32
-rw-r--r--src/rustdoc/parse.rs6
-rwxr-xr-xsrc/rustdoc/rustdoc.rs4
-rw-r--r--src/test/bench/core-std.rs8
-rw-r--r--src/test/bench/shootout-fasta.rs3
-rw-r--r--src/test/bench/shootout-k-nucleotide-pipes.rs8
-rw-r--r--src/test/bench/shootout-k-nucleotide.rs8
-rw-r--r--src/test/bench/shootout-mandelbrot.rs2
-rw-r--r--src/test/bench/task-perf-word-count-generic.rs2
43 files changed, 1135 insertions, 1111 deletions
diff --git a/src/cargo/cargo.rs b/src/cargo/cargo.rs
index 2330078a7bb..abd50520f50 100644
--- a/src/cargo/cargo.rs
+++ b/src/cargo/cargo.rs
@@ -43,12 +43,12 @@ type source = @{
 
 type cargo = {
     pgp: bool,
-    root: ~str,
-    installdir: ~str,
-    bindir: ~str,
-    libdir: ~str,
-    workdir: ~str,
-    sourcedir: ~str,
+    root: Path,
+    installdir: Path,
+    bindir: Path,
+    libdir: Path,
+    workdir: Path,
+    sourcedir: Path,
     sources: map::hashmap<~str, source>,
     mut current_install: ~str,
     dep_cache: map::hashmap<~str, bool>,
@@ -185,7 +185,7 @@ fn has_archive_extension(p: ~str) -> bool {
 }
 
 fn is_archive_path(u: ~str) -> bool {
-    has_archive_extension(u) && os::path_exists(u)
+    has_archive_extension(u) && os::path_exists(&Path(u))
 }
 
 fn is_archive_url(u: ~str) -> bool {
@@ -209,7 +209,7 @@ fn assume_source_method(url: ~str) -> ~str {
     if is_git_url(url) {
         return ~"git";
     }
-    if str::starts_with(url, ~"file://") || os::path_exists(url) {
+    if str::starts_with(url, ~"file://") || os::path_exists(&Path(url)) {
         return ~"file";
     }
 
@@ -238,7 +238,7 @@ fn load_link(mis: ~[@ast::meta_item]) -> (option<~str>,
     (name, vers, uuid)
 }
 
-fn load_crate(filename: ~str) -> option<crate> {
+fn load_crate(filename: &Path) -> option<crate> {
     let sess = parse::new_parse_sess(none);
     let c = parse::parse_crate_from_crate_file(filename, ~[], sess);
 
@@ -368,10 +368,10 @@ fn rest(s: ~str, start: uint) -> ~str {
     }
 }
 
-fn need_dir(s: ~str) {
+fn need_dir(s: &Path) {
     if os::path_is_dir(s) { return; }
     if !os::make_dir(s, 493_i32 /* oct: 755 */) {
-        fail fmt!("can't make_dir %s", s);
+        fail fmt!("can't make_dir %s", s.to_str());
     }
 }
 
@@ -411,7 +411,7 @@ fn parse_source(name: ~str, j: json::json) -> source {
                 _ => none
             };
             if method == ~"file" {
-                url = os::make_absolute(url);
+                url = os::make_absolute(&Path(url)).to_str();
             }
             return @{
                 name: name,
@@ -425,7 +425,7 @@ fn parse_source(name: ~str, j: json::json) -> source {
     };
 }
 
-fn try_parse_sources(filename: ~str, sources: map::hashmap<~str, source>) {
+fn try_parse_sources(filename: &Path, sources: map::hashmap<~str, source>) {
     if !os::path_exists(filename)  { return; }
     let c = io::read_whole_file_str(filename);
     match json::from_str(result::get(c)) {
@@ -436,7 +436,7 @@ fn try_parse_sources(filename: ~str, sources: map::hashmap<~str, source>) {
             }
         }
         ok(_) => fail ~"malformed sources.json",
-        err(e) => fail fmt!("%s:%s", filename, e.to_str())
+        err(e) => fail fmt!("%s:%s", filename.to_str(), e.to_str())
     }
 }
 
@@ -543,10 +543,10 @@ fn load_one_source_package(src: source, p: map::hashmap<~str, json::json>) {
 }
 
 fn load_source_info(c: cargo, src: source) {
-    let dir = path::connect(c.sourcedir, src.name);
-    let srcfile = path::connect(dir, ~"source.json");
-    if !os::path_exists(srcfile) { return; }
-    let srcstr = io::read_whole_file_str(srcfile);
+    let dir = c.sourcedir.push(src.name);
+    let srcfile = dir.push("source.json");
+    if !os::path_exists(&srcfile) { return; }
+    let srcstr = io::read_whole_file_str(&srcfile);
     match json::from_str(result::get(srcstr)) {
         ok(json::dict(s)) => {
             let o = parse_source(src.name, json::dict(s));
@@ -565,10 +565,10 @@ fn load_source_info(c: cargo, src: source) {
 }
 fn load_source_packages(c: cargo, src: source) {
     log(debug, ~"loading source: " + src.name);
-    let dir = path::connect(c.sourcedir, src.name);
-    let pkgfile = path::connect(dir, ~"packages.json");
-    if !os::path_exists(pkgfile) { return; }
-    let pkgstr = io::read_whole_file_str(pkgfile);
+    let dir = c.sourcedir.push(src.name);
+    let pkgfile = dir.push("packages.json");
+    if !os::path_exists(&pkgfile) { return; }
+    let pkgstr = io::read_whole_file_str(&pkgfile);
     match json::from_str(result::get(pkgstr)) {
         ok(json::list(js)) => {
           for (*js).each |j| {
@@ -639,8 +639,8 @@ fn configure(opts: options) -> cargo {
     let p = result::get(get_cargo_dir());
 
     let sources = map::str_hash();
-    try_parse_sources(path::connect(home, ~"sources.json"), sources);
-    try_parse_sources(path::connect(home, ~"local-sources.json"), sources);
+    try_parse_sources(&home.push("sources.json"), sources);
+    try_parse_sources(&home.push("local-sources.json"), sources);
 
     let dep_cache = map::str_hash();
 
@@ -648,22 +648,22 @@ fn configure(opts: options) -> cargo {
         pgp: pgp::supported(),
         root: home,
         installdir: p,
-        bindir: path::connect(p, ~"bin"),
-        libdir: path::connect(p, ~"lib"),
-        workdir: path::connect(p, ~"work"),
-        sourcedir: path::connect(home, ~"sources"),
+        bindir: p.push("bin"),
+        libdir: p.push("lib"),
+        workdir: p.push("work"),
+        sourcedir: home.push("sources"),
         sources: sources,
         mut current_install: ~"",
         dep_cache: dep_cache,
         opts: opts
     };
 
-    need_dir(c.root);
-    need_dir(c.installdir);
-    need_dir(c.sourcedir);
-    need_dir(c.workdir);
-    need_dir(c.libdir);
-    need_dir(c.bindir);
+    need_dir(&c.root);
+    need_dir(&c.installdir);
+    need_dir(&c.sourcedir);
+    need_dir(&c.workdir);
+    need_dir(&c.libdir);
+    need_dir(&c.bindir);
 
     for sources.each_key |k| {
         let mut s = sources.get(k);
@@ -672,7 +672,7 @@ fn configure(opts: options) -> cargo {
     }
 
     if c.pgp {
-        pgp::init(c.root);
+        pgp::init(&c.root);
     } else {
         warn(~"command `gpg` was not found");
         warn(~"you have to install gpg from source " +
@@ -694,22 +694,24 @@ fn for_each_package(c: cargo, b: fn(source, package)) {
 }
 
 // Runs all programs in directory <buildpath>
-fn run_programs(buildpath: ~str) {
+fn run_programs(buildpath: &Path) {
     let newv = os::list_dir_path(buildpath);
     for newv.each |ct| {
-        run::run_program(ct, ~[]);
+        run::run_program(ct.to_str(), ~[]);
     }
 }
 
 // Runs rustc in <path + subdir> with the given flags
-// and returns <path + subdir>
-fn run_in_buildpath(what: ~str, path: ~str, subdir: ~str, cf: ~str,
-                    extra_flags: ~[~str]) -> option<~str> {
-    let buildpath = path::connect(path, subdir);
-    need_dir(buildpath);
-    debug!("%s: %s -> %s", what, cf, buildpath);
+// and returns <patho + subdir>
+fn run_in_buildpath(what: &str, path: &Path, subdir: &Path, cf: &Path,
+                    extra_flags: ~[~str]) -> option<Path> {
+    let buildpath = path.push_rel(subdir);
+    need_dir(&buildpath);
+    debug!("%s: %s -> %s", what, cf.to_str(), buildpath.to_str());
     let p = run::program_output(rustc_sysroot(),
-                                ~[~"--out-dir", buildpath, cf] + extra_flags);
+                                ~[~"--out-dir",
+                                  buildpath.to_str(),
+                                  cf.to_str()] + extra_flags);
     if p.status != 0 {
         error(fmt!("rustc failed: %d\n%s\n%s", p.status, p.err, p.out));
         return none;
@@ -717,37 +719,42 @@ fn run_in_buildpath(what: ~str, path: ~str, subdir: ~str, cf: ~str,
     some(buildpath)
 }
 
-fn test_one_crate(_c: cargo, path: ~str, cf: ~str) {
-  let buildpath = match run_in_buildpath(~"testing", path, ~"/test", cf,
-                                       ~[ ~"--test"]) {
+fn test_one_crate(_c: cargo, path: &Path, cf: &Path) {
+    let buildpath = match run_in_buildpath(~"testing", path,
+                                           &Path("test"),
+                                           cf,
+                                           ~[ ~"--test"]) {
       none => return,
-      some(bp) => bp
+    some(bp) => bp
   };
-  run_programs(buildpath);
+  run_programs(&buildpath);
 }
 
-fn install_one_crate(c: cargo, path: ~str, cf: ~str) {
+fn install_one_crate(c: cargo, path: &Path, cf: &Path) {
     let buildpath = match run_in_buildpath(~"installing", path,
-                                         ~"/build", cf, ~[]) {
+                                           &Path("build"),
+                                           cf, ~[]) {
       none => return,
       some(bp) => bp
     };
-    let newv = os::list_dir_path(buildpath);
+    let newv = os::list_dir_path(&buildpath);
     let exec_suffix = os::exe_suffix();
     for newv.each |ct| {
-        if (exec_suffix != ~"" && str::ends_with(ct, exec_suffix)) ||
-            (exec_suffix == ~"" && !str::starts_with(path::basename(ct),
-                                                    ~"lib")) {
-            debug!("  bin: %s", ct);
-            install_to_dir(ct, c.bindir);
+        if (exec_suffix != ~"" && str::ends_with(ct.to_str(),
+                                                 exec_suffix)) ||
+            (exec_suffix == ~"" &&
+             !str::starts_with(option::get(ct.filename()),
+                               ~"lib")) {
+            debug!("  bin: %s", ct.to_str());
+            install_to_dir(ct, &c.bindir);
             if c.opts.mode == system_mode {
                 // FIXME (#2662): Put this file in PATH / symlink it so it can
                 // be used as a generic executable
                 // `cargo install -G rustray` and `rustray file.obj`
             }
         } else {
-            debug!("  lib: %s", ct);
-            install_to_dir(ct, c.libdir);
+            debug!("  lib: %s", ct.to_str());
+            install_to_dir(ct, &c.libdir);
         }
     }
 }
@@ -756,23 +763,22 @@ fn install_one_crate(c: cargo, path: ~str, cf: ~str) {
 fn rustc_sysroot() -> ~str {
     match os::self_exe_path() {
         some(path) => {
-            let path = ~[path, ~"..", ~"bin", ~"rustc"];
-            let rustc = path::normalize(path::connect_many(path));
-            debug!("  rustc: %s", rustc);
-            rustc
+            let rustc = path.push_many([~"..", ~"bin", ~"rustc"]);
+            debug!("  rustc: %s", rustc.to_str());
+            rustc.to_str()
         }
         none => ~"rustc"
     }
 }
 
-fn install_source(c: cargo, path: ~str) {
-    debug!("source: %s", path);
+fn install_source(c: cargo, path: &Path) {
+    debug!("source: %s", path.to_str());
     os::change_dir(path);
 
     let mut cratefiles = ~[];
-    for os::walk_dir(~".") |p| {
-        if str::ends_with(p, ~".rc") {
-            vec::push(cratefiles, p);
+    for os::walk_dir(&Path(".")) |p| {
+        if p.filetype() == some(~"rc") {
+            vec::push(cratefiles, *p);
         }
     }
 
@@ -781,7 +787,7 @@ fn install_source(c: cargo, path: ~str) {
     }
 
     for cratefiles.each |cf| {
-        match load_crate(cf) {
+        match load_crate(&cf) {
             none => again,
             some(crate) => {
               for crate.deps.each |query| {
@@ -789,28 +795,23 @@ fn install_source(c: cargo, path: ~str) {
                     // (n.b. #1356 says "Cyclic dependency is an error
                     // condition")
 
-                    let wd_base = c.workdir + path::path_sep();
-                    let wd = match tempfile::mkdtemp(wd_base, ~"") {
-                        some(wd) => wd,
-                        none => fail fmt!("needed temp dir: %s", wd_base)
-                    };
-
-                    install_query(c, wd, query);
+                    let wd = get_temp_workdir(c);
+                    install_query(c, &wd, query);
                 }
 
                 os::change_dir(path);
 
                 if c.opts.test {
-                    test_one_crate(c, path, cf);
+                    test_one_crate(c, path, &cf);
                 }
-                install_one_crate(c, path, cf);
+                install_one_crate(c, path, &cf);
             }
         }
     }
 }
 
-fn install_git(c: cargo, wd: ~str, url: ~str, reference: option<~str>) {
-    run::program_output(~"git", ~[~"clone", url, wd]);
+fn install_git(c: cargo, wd: &Path, url: ~str, reference: option<~str>) {
+    run::program_output(~"git", ~[~"clone", url, wd.to_str()]);
     if option::is_some(reference) {
         let r = option::get(reference);
         os::change_dir(wd);
@@ -820,25 +821,27 @@ fn install_git(c: cargo, wd: ~str, url: ~str, reference: option<~str>) {
     install_source(c, wd);
 }
 
-fn install_curl(c: cargo, wd: ~str, url: ~str) {
-    let tarpath = path::connect(wd, ~"pkg.tar");
+fn install_curl(c: cargo, wd: &Path, url: ~str) {
+    let tarpath = wd.push("pkg.tar");
     let p = run::program_output(~"curl", ~[~"-f", ~"-s", ~"-o",
-                                         tarpath, url]);
+                                         tarpath.to_str(), url]);
     if p.status != 0 {
         fail fmt!("fetch of %s failed: %s", url, p.err);
     }
     run::run_program(~"tar", ~[~"-x", ~"--strip-components=1",
-                             ~"-C", wd, ~"-f", tarpath]);
+                               ~"-C", wd.to_str(),
+                               ~"-f", tarpath.to_str()]);
     install_source(c, wd);
 }
 
-fn install_file(c: cargo, wd: ~str, path: ~str) {
+fn install_file(c: cargo, wd: &Path, path: &Path) {
     run::program_output(~"tar", ~[~"-x", ~"--strip-components=1",
-                             ~"-C", wd, ~"-f", path]);
+                                  ~"-C", wd.to_str(),
+                                  ~"-f", path.to_str()]);
     install_source(c, wd);
 }
 
-fn install_package(c: cargo, src: ~str, wd: ~str, pkg: package) {
+fn install_package(c: cargo, src: ~str, wd: &Path, pkg: package) {
     let url = copy pkg.url;
     let method = match pkg.method {
         ~"git" => ~"git",
@@ -850,7 +853,7 @@ fn install_package(c: cargo, src: ~str, wd: ~str, pkg: package) {
 
     match method {
         ~"git" => install_git(c, wd, url, copy pkg.reference),
-        ~"file" => install_file(c, wd, url),
+        ~"file" => install_file(c, wd, &Path(url)),
         ~"curl" => install_curl(c, wd, copy url),
         _ => ()
     }
@@ -866,7 +869,7 @@ fn cargo_suggestion(c: cargo, fallback: fn())
     fallback();
 }
 
-fn install_uuid(c: cargo, wd: ~str, uuid: ~str) {
+fn install_uuid(c: cargo, wd: &Path, uuid: ~str) {
     let mut ps = ~[];
     for_each_package(c, |s, p| {
         if p.uuid == uuid {
@@ -890,7 +893,7 @@ fn install_uuid(c: cargo, wd: ~str, uuid: ~str) {
     }
 }
 
-fn install_named(c: cargo, wd: ~str, name: ~str) {
+fn install_named(c: cargo, wd: &Path, name: ~str) {
     let mut ps = ~[];
     for_each_package(c, |s, p| {
         if p.name == name {
@@ -914,7 +917,7 @@ fn install_named(c: cargo, wd: ~str, name: ~str) {
     }
 }
 
-fn install_uuid_specific(c: cargo, wd: ~str, src: ~str, uuid: ~str) {
+fn install_uuid_specific(c: cargo, wd: &Path, src: ~str, uuid: ~str) {
     match c.sources.find(src) {
       some(s) => {
         let packages = copy s.packages;
@@ -930,7 +933,7 @@ fn install_uuid_specific(c: cargo, wd: ~str, src: ~str, uuid: ~str) {
     error(~"can't find package: " + src + ~"/" + uuid);
 }
 
-fn install_named_specific(c: cargo, wd: ~str, src: ~str, name: ~str) {
+fn install_named_specific(c: cargo, wd: &Path, src: ~str, name: ~str) {
     match c.sources.find(src) {
         some(s) => {
           let packages = copy s.packages;
@@ -952,59 +955,45 @@ fn cmd_uninstall(c: cargo) {
         return;
     }
 
-    let lib = c.libdir;
-    let bin = c.bindir;
+    let lib = &c.libdir;
+    let bin = &c.bindir;
     let target = c.opts.free[2u];
 
     // FIXME (#2662): needs stronger pattern matching
     // FIXME (#2662): needs to uninstall from a specified location in a
     // cache instead of looking for it (binaries can be uninstalled by
     // name only)
+
+    fn try_uninstall(p: &Path) -> bool {
+        if os::remove_file(p) {
+            info(~"uninstalled: '" + p.to_str() + ~"'");
+            true
+        } else {
+            error(~"could not uninstall: '" +
+                  p.to_str() + ~"'");
+            false
+        }
+    }
+
     if is_uuid(target) {
         for os::list_dir(lib).each |file| {
             match str::find_str(file, ~"-" + target + ~"-") {
-                some(idx) => {
-                    let full = path::normalize(path::connect(lib, file));
-                    if os::remove_file(full) {
-                        info(~"uninstalled: '" + full + ~"'");
-                    } else {
-                        error(~"could not uninstall: '" + full + ~"'");
-                    }
-                    return;
-                }
-                none => again
+              some(_) => if !try_uninstall(&lib.push(file)) { return },
+              none => ()
             }
         }
-
         error(~"can't find package with uuid: " + target);
     } else {
         for os::list_dir(lib).each |file| {
             match str::find_str(file, ~"lib" + target + ~"-") {
-                some(idx) => {
-                    let full = path::normalize(path::connect(lib,
-                               file));
-                    if os::remove_file(full) {
-                        info(~"uninstalled: '" + full + ~"'");
-                    } else {
-                        error(~"could not uninstall: '" + full + ~"'");
-                    }
-                    return;
-                }
-                none => again
+              some(_) => if !try_uninstall(&lib.push(file)) { return },
+              none => ()
             }
         }
         for os::list_dir(bin).each |file| {
             match str::find_str(file, target) {
-                some(idx) => {
-                    let full = path::normalize(path::connect(bin, file));
-                    if os::remove_file(full) {
-                        info(~"uninstalled: '" + full + ~"'");
-                    } else {
-                        error(~"could not uninstall: '" + full + ~"'");
-                    }
-                    return;
-                }
-                none => again
+              some(_) => if !try_uninstall(&lib.push(file)) { return },
+              none => ()
             }
         }
 
@@ -1012,7 +1001,7 @@ fn cmd_uninstall(c: cargo) {
     }
 }
 
-fn install_query(c: cargo, wd: ~str, target: ~str) {
+fn install_query(c: cargo, wd: &Path, target: ~str) {
     match c.dep_cache.find(target) {
         some(inst) => {
             if inst {
@@ -1025,7 +1014,7 @@ fn install_query(c: cargo, wd: ~str, target: ~str) {
     c.dep_cache.insert(target, true);
 
     if is_archive_path(target) {
-        install_file(c, wd, target);
+        install_file(c, wd, &Path(target));
         return;
     } else if is_git_url(target) {
         let reference = if c.opts.free.len() >= 4u {
@@ -1072,31 +1061,36 @@ fn install_query(c: cargo, wd: ~str, target: ~str) {
     }
 }
 
+fn get_temp_workdir(c: cargo) -> Path {
+    match tempfile::mkdtemp(&c.workdir, "cargo") {
+      some(wd) => wd,
+      none => fail fmt!("needed temp dir: %s",
+                        c.workdir.to_str())
+    }
+}
+
 fn cmd_install(c: cargo) unsafe {
-    let wd_base = c.workdir + path::path_sep();
-    let wd = match tempfile::mkdtemp(wd_base, ~"") {
-        some(wd) => wd,
-        none => fail fmt!("needed temp dir: %s", wd_base)
-    };
+    let wd = get_temp_workdir(c);
 
     if vec::len(c.opts.free) == 2u {
         let cwd = os::getcwd();
-        let status = run::run_program(~"cp", ~[~"-R", cwd, wd]);
+        let status = run::run_program(~"cp", ~[~"-R", cwd.to_str(),
+                                               wd.to_str()]);
 
         if status != 0 {
-            fail fmt!("could not copy directory: %s", cwd);
+            fail fmt!("could not copy directory: %s", cwd.to_str());
         }
 
-        install_source(c, wd);
+        install_source(c, &wd);
         return;
     }
 
     sync(c);
 
     let query = c.opts.free[2];
-    c.current_install = copy query;
+    c.current_install = query.to_str();
 
-    install_query(c, wd, copy query);
+    install_query(c, &wd, query);
 }
 
 fn sync(c: cargo) {
@@ -1107,45 +1101,47 @@ fn sync(c: cargo) {
     }
 }
 
-fn sync_one_file(c: cargo, dir: ~str, src: source) -> bool {
+fn sync_one_file(c: cargo, dir: &Path, src: source) -> bool {
     let name = src.name;
-    let srcfile = path::connect(dir, ~"source.json.new");
-    let destsrcfile = path::connect(dir, ~"source.json");
-    let pkgfile = path::connect(dir, ~"packages.json.new");
-    let destpkgfile = path::connect(dir, ~"packages.json");
-    let keyfile = path::connect(dir, ~"key.gpg");
-    let srcsigfile = path::connect(dir, ~"source.json.sig");
-    let sigfile = path::connect(dir, ~"packages.json.sig");
-    let url = src.url;
+    let srcfile = dir.push("source.json.new");
+    let destsrcfile = dir.push("source.json");
+    let pkgfile = dir.push("packages.json.new");
+    let destpkgfile = dir.push("packages.json");
+    let keyfile = dir.push("key.gpg");
+    let srcsigfile = dir.push("source.json.sig");
+    let sigfile = dir.push("packages.json.sig");
+    let url = Path(src.url);
     let mut has_src_file = false;
 
-    if !os::copy_file(path::connect(url, ~"packages.json"), pkgfile) {
-        error(fmt!("fetch for source %s (url %s) failed", name, url));
+    if !os::copy_file(&url.push("packages.json"), &pkgfile) {
+        error(fmt!("fetch for source %s (url %s) failed",
+                   name, url.to_str()));
         return false;
     }
 
-    if os::copy_file(path::connect(url, ~"source.json"), srcfile) {
+    if os::copy_file(&url.push("source.json"), &srcfile) {
         has_src_file = false;
     }
 
-    os::copy_file(path::connect(url, ~"source.json.sig"), srcsigfile);
-    os::copy_file(path::connect(url, ~"packages.json.sig"), sigfile);
+    os::copy_file(&url.push("source.json.sig"), &srcsigfile);
+    os::copy_file(&url.push("packages.json.sig"), &sigfile);
 
     match copy src.key {
         some(u) => {
             let p = run::program_output(~"curl",
-                                        ~[~"-f", ~"-s", ~"-o", keyfile, u]);
+                                        ~[~"-f", ~"-s",
+                                          ~"-o", keyfile.to_str(), u]);
             if p.status != 0 {
                 error(fmt!("fetch for source %s (key %s) failed", name, u));
                 return false;
             }
-            pgp::add(c.root, keyfile);
+            pgp::add(&c.root, &keyfile);
         }
         _ => ()
     }
     match (src.key, src.keyfp) {
         (some(_), some(f)) => {
-            let r = pgp::verify(c.root, pkgfile, sigfile, f);
+            let r = pgp::verify(&c.root, &pkgfile, &sigfile, f);
 
             if !r {
                 error(fmt!("signature verification failed for source %s",
@@ -1154,7 +1150,7 @@ fn sync_one_file(c: cargo, dir: ~str, src: source) -> bool {
             }
 
             if has_src_file {
-                let e = pgp::verify(c.root, srcfile, srcsigfile, f);
+                let e = pgp::verify(&c.root, &srcfile, &srcsigfile, f);
 
                 if !e {
                     error(fmt!("signature verification failed for source %s",
@@ -1166,33 +1162,33 @@ fn sync_one_file(c: cargo, dir: ~str, src: source) -> bool {
         _ => ()
     }
 
-    copy_warn(pkgfile, destpkgfile);
+    copy_warn(&pkgfile, &destpkgfile);
 
     if has_src_file {
-        copy_warn(srcfile, destsrcfile);
+        copy_warn(&srcfile, &destsrcfile);
     }
 
-    os::remove_file(keyfile);
-    os::remove_file(srcfile);
-    os::remove_file(srcsigfile);
-    os::remove_file(pkgfile);
-    os::remove_file(sigfile);
+    os::remove_file(&keyfile);
+    os::remove_file(&srcfile);
+    os::remove_file(&srcsigfile);
+    os::remove_file(&pkgfile);
+    os::remove_file(&sigfile);
 
     info(fmt!("synced source: %s", name));
 
     return true;
 }
 
-fn sync_one_git(c: cargo, dir: ~str, src: source) -> bool {
+fn sync_one_git(c: cargo, dir: &Path, src: source) -> bool {
     let name = src.name;
-    let srcfile = path::connect(dir, ~"source.json");
-    let pkgfile = path::connect(dir, ~"packages.json");
-    let keyfile = path::connect(dir, ~"key.gpg");
-    let srcsigfile = path::connect(dir, ~"source.json.sig");
-    let sigfile = path::connect(dir, ~"packages.json.sig");
+    let srcfile = dir.push("source.json");
+    let pkgfile = dir.push("packages.json");
+    let keyfile = dir.push("key.gpg");
+    let srcsigfile = dir.push("source.json.sig");
+    let sigfile = dir.push("packages.json.sig");
     let url = src.url;
 
-    fn rollback(name: ~str, dir: ~str, insecure: bool) {
+    fn rollback(name: ~str, dir: &Path, insecure: bool) {
         fn msg(name: ~str, insecure: bool) {
             error(fmt!("could not rollback source: %s", name));
 
@@ -1216,8 +1212,8 @@ fn sync_one_git(c: cargo, dir: ~str, src: source) -> bool {
         }
     }
 
-    if !os::path_exists(path::connect(dir, ~".git")) {
-        let p = run::program_output(~"git", ~[~"clone", url, dir]);
+    if !os::path_exists(&dir.push(".git")) {
+        let p = run::program_output(~"git", ~[~"clone", url, dir.to_str()]);
 
         if p.status != 0 {
             error(fmt!("fetch for source %s (url %s) failed", name, url));
@@ -1238,24 +1234,25 @@ fn sync_one_git(c: cargo, dir: ~str, src: source) -> bool {
         }
     }
 
-    let has_src_file = os::path_exists(srcfile);
+    let has_src_file = os::path_exists(&srcfile);
 
     match copy src.key {
         some(u) => {
             let p = run::program_output(~"curl",
-                                        ~[~"-f", ~"-s", ~"-o", keyfile, u]);
+                                        ~[~"-f", ~"-s",
+                                          ~"-o", keyfile.to_str(), u]);
             if p.status != 0 {
                 error(fmt!("fetch for source %s (key %s) failed", name, u));
                 rollback(name, dir, false);
                 return false;
             }
-            pgp::add(c.root, keyfile);
+            pgp::add(&c.root, &keyfile);
         }
         _ => ()
     }
     match (src.key, src.keyfp) {
         (some(_), some(f)) => {
-            let r = pgp::verify(c.root, pkgfile, sigfile, f);
+            let r = pgp::verify(&c.root, &pkgfile, &sigfile, f);
 
             if !r {
                 error(fmt!("signature verification failed for source %s",
@@ -1265,7 +1262,7 @@ fn sync_one_git(c: cargo, dir: ~str, src: source) -> bool {
             }
 
             if has_src_file {
-                let e = pgp::verify(c.root, srcfile, srcsigfile, f);
+                let e = pgp::verify(&c.root, &srcfile, &srcsigfile, f);
 
                 if !e {
                     error(fmt!("signature verification failed for source %s",
@@ -1278,22 +1275,22 @@ fn sync_one_git(c: cargo, dir: ~str, src: source) -> bool {
         _ => ()
     }
 
-    os::remove_file(keyfile);
+    os::remove_file(&keyfile);
 
     info(fmt!("synced source: %s", name));
 
     return true;
 }
 
-fn sync_one_curl(c: cargo, dir: ~str, src: source) -> bool {
+fn sync_one_curl(c: cargo, dir: &Path, src: source) -> bool {
     let name = src.name;
-    let srcfile = path::connect(dir, ~"source.json.new");
-    let destsrcfile = path::connect(dir, ~"source.json");
-    let pkgfile = path::connect(dir, ~"packages.json.new");
-    let destpkgfile = path::connect(dir, ~"packages.json");
-    let keyfile = path::connect(dir, ~"key.gpg");
-    let srcsigfile = path::connect(dir, ~"source.json.sig");
-    let sigfile = path::connect(dir, ~"packages.json.sig");
+    let srcfile = dir.push("source.json.new");
+    let destsrcfile = dir.push("source.json");
+    let pkgfile = dir.push("packages.json.new");
+    let destpkgfile = dir.push("packages.json");
+    let keyfile = dir.push("key.gpg");
+    let srcsigfile = dir.push("source.json.sig");
+    let sigfile = dir.push("packages.json.sig");
     let mut url = src.url;
     let smart = !str::ends_with(src.url, ~"packages.json");
     let mut has_src_file = false;
@@ -1303,7 +1300,8 @@ fn sync_one_curl(c: cargo, dir: ~str, src: source) -> bool {
     }
 
     let p = run::program_output(~"curl",
-                                ~[~"-f", ~"-s", ~"-o", pkgfile, url]);
+                                ~[~"-f", ~"-s",
+                                  ~"-o", pkgfile.to_str(), url]);
 
     if p.status != 0 {
         error(fmt!("fetch for source %s (url %s) failed", name, url));
@@ -1313,7 +1311,8 @@ fn sync_one_curl(c: cargo, dir: ~str, src: source) -> bool {
         url = src.url + ~"/source.json";
         let p =
             run::program_output(~"curl",
-                                ~[~"-f", ~"-s", ~"-o", srcfile, url]);
+                                ~[~"-f", ~"-s",
+                                  ~"-o", srcfile.to_str(), url]);
 
         if p.status == 0 {
             has_src_file = true;
@@ -1323,12 +1322,13 @@ fn sync_one_curl(c: cargo, dir: ~str, src: source) -> bool {
     match copy src.key {
         some(u) => {
             let p = run::program_output(~"curl",
-                                        ~[~"-f", ~"-s", ~"-o", keyfile, u]);
+                                        ~[~"-f", ~"-s",
+                                          ~"-o", keyfile.to_str(), u]);
             if p.status != 0 {
                 error(fmt!("fetch for source %s (key %s) failed", name, u));
                 return false;
             }
-            pgp::add(c.root, keyfile);
+            pgp::add(&c.root, &keyfile);
         }
         _ => ()
     }
@@ -1341,14 +1341,15 @@ fn sync_one_curl(c: cargo, dir: ~str, src: source) -> bool {
                 url = src.url + ~".sig";
             }
 
-            let mut p = run::program_output(~"curl", ~[~"-f", ~"-s", ~"-o",
-                        sigfile, url]);
+            let mut p = run::program_output(~"curl",
+                                            ~[~"-f", ~"-s", ~"-o",
+                                              sigfile.to_str(), url]);
             if p.status != 0 {
                 error(fmt!("fetch for source %s (sig %s) failed", name, url));
                 return false;
             }
 
-            let r = pgp::verify(c.root, pkgfile, sigfile, f);
+            let r = pgp::verify(&c.root, &pkgfile, &sigfile, f);
 
             if !r {
                 error(fmt!("signature verification failed for source %s",
@@ -1361,14 +1362,14 @@ fn sync_one_curl(c: cargo, dir: ~str, src: source) -> bool {
 
                 p = run::program_output(~"curl",
                                         ~[~"-f", ~"-s", ~"-o",
-                                          srcsigfile, url]);
+                                          srcsigfile.to_str(), url]);
                 if p.status != 0 {
                     error(fmt!("fetch for source %s (sig %s) failed",
                           name, url));
                     return false;
                 }
 
-                let e = pgp::verify(c.root, srcfile, srcsigfile, f);
+                let e = pgp::verify(&c.root, &srcfile, &srcsigfile, f);
 
                 if !e {
                     error(~"signature verification failed for " +
@@ -1380,17 +1381,17 @@ fn sync_one_curl(c: cargo, dir: ~str, src: source) -> bool {
         _ => ()
     }
 
-    copy_warn(pkgfile, destpkgfile);
+    copy_warn(&pkgfile, &destpkgfile);
 
     if smart && has_src_file {
-        copy_warn(srcfile, destsrcfile);
+        copy_warn(&srcfile, &destsrcfile);
     }
 
-    os::remove_file(keyfile);
-    os::remove_file(srcfile);
-    os::remove_file(srcsigfile);
-    os::remove_file(pkgfile);
-    os::remove_file(sigfile);
+    os::remove_file(&keyfile);
+    os::remove_file(&srcfile);
+    os::remove_file(&srcsigfile);
+    os::remove_file(&pkgfile);
+    os::remove_file(&sigfile);
 
     info(fmt!("synced source: %s", name));
 
@@ -1399,16 +1400,16 @@ fn sync_one_curl(c: cargo, dir: ~str, src: source) -> bool {
 
 fn sync_one(c: cargo, src: source) {
     let name = src.name;
-    let dir = path::connect(c.sourcedir, name);
+    let dir = c.sourcedir.push(name);
 
     info(fmt!("syncing source: %s...", name));
 
-    need_dir(dir);
+    need_dir(&dir);
 
     let result = match src.method {
-        ~"git" => sync_one_git(c, dir, src),
-        ~"file" => sync_one_file(c, dir, src),
-        _ => sync_one_curl(c, dir, src)
+        ~"git" => sync_one_git(c, &dir, src),
+        ~"file" => sync_one_file(c, &dir, src),
+        _ => sync_one_curl(c, &dir, src)
     };
 
     if result {
@@ -1421,35 +1422,39 @@ fn cmd_init(c: cargo) {
     let srcurl = ~"http://www.rust-lang.org/cargo/sources.json";
     let sigurl = ~"http://www.rust-lang.org/cargo/sources.json.sig";
 
-    let srcfile = path::connect(c.root, ~"sources.json.new");
-    let sigfile = path::connect(c.root, ~"sources.json.sig");
-    let destsrcfile = path::connect(c.root, ~"sources.json");
+    let srcfile = c.root.push("sources.json.new");
+    let sigfile = c.root.push("sources.json.sig");
+    let destsrcfile = c.root.push("sources.json");
 
     let p =
-        run::program_output(~"curl", ~[~"-f", ~"-s", ~"-o", srcfile, srcurl]);
+        run::program_output(~"curl", ~[~"-f", ~"-s",
+                                       ~"-o", srcfile.to_str(), srcurl]);
     if p.status != 0 {
         error(fmt!("fetch of sources.json failed: %s", p.out));
         return;
     }
 
     let p =
-        run::program_output(~"curl", ~[~"-f", ~"-s", ~"-o", sigfile, sigurl]);
+        run::program_output(~"curl", ~[~"-f", ~"-s",
+                                       ~"-o", sigfile.to_str(), sigurl]);
     if p.status != 0 {
         error(fmt!("fetch of sources.json.sig failed: %s", p.out));
         return;
     }
 
-    let r = pgp::verify(c.root, srcfile, sigfile, pgp::signing_key_fp());
+    let r = pgp::verify(&c.root, &srcfile, &sigfile,
+                        pgp::signing_key_fp());
     if !r {
-        error(fmt!("signature verification failed for '%s'", srcfile));
+        error(fmt!("signature verification failed for '%s'",
+                   srcfile.to_str()));
         return;
     }
 
-    copy_warn(srcfile, destsrcfile);
-    os::remove_file(srcfile);
-    os::remove_file(sigfile);
+    copy_warn(&srcfile, &destsrcfile);
+    os::remove_file(&srcfile);
+    os::remove_file(&sigfile);
 
-    info(fmt!("initialized .cargo in %s", c.root));
+    info(fmt!("initialized .cargo in %s", c.root.to_str()));
 }
 
 fn print_pkg(s: source, p: package) {
@@ -1530,25 +1535,26 @@ fn cmd_search(c: cargo) {
     info(fmt!("found %d packages", n));
 }
 
-fn install_to_dir(srcfile: ~str, destdir: ~str) {
-    let newfile = path::connect(destdir, path::basename(srcfile));
+fn install_to_dir(srcfile: &Path, destdir: &Path) {
+    let newfile = destdir.push(option::get(srcfile.filename()));
 
-    let status = run::run_program(~"cp", ~[~"-r", srcfile, newfile]);
+    let status = run::run_program(~"cp", ~[~"-r", srcfile.to_str(),
+                                           newfile.to_str()]);
     if status == 0 {
-        info(fmt!("installed: '%s'", newfile));
+        info(fmt!("installed: '%s'", newfile.to_str()));
     } else {
-        error(fmt!("could not install: '%s'", newfile));
+        error(fmt!("could not install: '%s'", newfile.to_str()));
     }
 }
 
 fn dump_cache(c: cargo) {
-    need_dir(c.root);
+    need_dir(&c.root);
 
-    let out = path::connect(c.root, ~"cache.json");
+    let out = c.root.push("cache.json");
     let _root = json::dict(map::str_hash());
 
-    if os::path_exists(out) {
-        copy_warn(out, path::connect(c.root, ~"cache.json.old"));
+    if os::path_exists(&out) {
+        copy_warn(&out, &c.root.push("cache.json.old"));
     }
 }
 fn dump_sources(c: cargo) {
@@ -1556,15 +1562,15 @@ fn dump_sources(c: cargo) {
         return;
     }
 
-    need_dir(c.root);
+    need_dir(&c.root);
 
-    let out = path::connect(c.root, ~"sources.json");
+    let out = c.root.push("sources.json");
 
-    if os::path_exists(out) {
-        copy_warn(out, path::connect(c.root, ~"sources.json.old"));
+    if os::path_exists(&out) {
+        copy_warn(&out, &c.root.push("sources.json.old"));
     }
 
-    match io::buffered_file_writer(out) {
+    match io::buffered_file_writer(&out) {
         result::ok(writer) => {
             let hash = map::str_hash();
             let root = json::dict(hash);
@@ -1600,9 +1606,10 @@ fn dump_sources(c: cargo) {
     }
 }
 
-fn copy_warn(srcfile: ~str, destfile: ~str) {
+fn copy_warn(srcfile: &Path, destfile: &Path) {
     if !os::copy_file(srcfile, destfile) {
-        warn(fmt!("copying %s to %s failed", srcfile, destfile));
+        warn(fmt!("copying %s to %s failed",
+                  srcfile.to_str(), destfile.to_str()));
     }
 }
 
@@ -1894,7 +1901,7 @@ fn main(argv: ~[~str]) {
 
     let mut c = configure(o);
     let home = c.root;
-    let first_time = os::path_exists(path::connect(home, ~"sources.json"));
+    let first_time = os::path_exists(&home.push("sources.json"));
 
     if !first_time && o.free[1] != ~"init" {
         cmd_init(c);
diff --git a/src/cargo/pgp.rs b/src/cargo/pgp.rs
index c79d7f3bcf3..17f3a2060aa 100644
--- a/src/cargo/pgp.rs
+++ b/src/cargo/pgp.rs
@@ -63,11 +63,13 @@ fn supported() -> bool {
     r.status == 0
 }
 
-fn init(root: ~str) {
-    let p = path::connect(root, ~"gpg");
-    if !os::path_is_dir(p) {
-        os::make_dir(p, 0x1c0i32);
-        let p = run::start_program(~"gpg", ~[~"--homedir", p, ~"--import"]);
+fn init(root: &Path) {
+    let p = root.push("gpg");
+    if !os::path_is_dir(&p) {
+        os::make_dir(&p, 0x1c0i32);
+        let p = run::start_program(~"gpg", ~[~"--homedir",
+                                             p.to_str(),
+                                             ~"--import"]);
         p.input().write_str(signing_key());
         let s = p.finish();
         if s != 0 {
@@ -76,19 +78,22 @@ fn init(root: ~str) {
     }
 }
 
-fn add(root: ~str, key: ~str) {
-    let path = path::connect(root, ~"gpg");
+fn add(root: &Path, key: &Path) {
+    let path = root.push("gpg");
     let p =
-        run::program_output(~"gpg", ~[~"--homedir", path, ~"--import", key]);
+        run::program_output(~"gpg", ~[~"--homedir", path.to_str(),
+                                      ~"--import", key.to_str()]);
     if p.status != 0 {
         fail ~"pgp add failed: " + p.out;
     }
 }
 
-fn verify(root: ~str, data: ~str, sig: ~str, keyfp: ~str) -> bool {
-    let path = path::connect(root, ~"gpg");
-    let p = gpg(~[~"--homedir", path, ~"--with-fingerprint", ~"--verify", sig,
-                 data]);
+fn verify(root: &Path, data: &Path, sig: &Path, keyfp: ~str) -> bool {
+    let path = root.push("gpg");
+    let p = gpg(~[~"--homedir", path.to_str(),
+                  ~"--with-fingerprint",
+                  ~"--verify", sig.to_str(),
+                 data.to_str()]);
     let res = ~"Primary key fingerprint: " + keyfp;
     for str::split_char(p.err, '\n').each |line| {
         if line == res { return true; }
diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs
index a7bcc8d67cc..021b138ffc1 100644
--- a/src/compiletest/common.rs
+++ b/src/compiletest/common.rs
@@ -10,16 +10,16 @@ type config = {
     run_lib_path: ~str,
 
     // The rustc executable
-    rustc_path: ~str,
+    rustc_path: Path,
 
     // The directory containing the tests to run
-    src_base: ~str,
+    src_base: Path,
 
     // The directory where programs should be built
-    build_base: ~str,
+    build_base: Path,
 
     // Directory for auxiliary libraries
-    aux_base: ~str,
+    aux_base: Path,
 
     // The name of the stage being built (stage1, etc)
     stage_id: ~str,
@@ -34,7 +34,7 @@ type config = {
     filter: option<~str>,
 
     // Write out a parseable log of tests that were run
-    logfile: option<~str>,
+    logfile: option<Path>,
 
     // A command line to prefix program execution with,
     // for running under valgrind
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs
index 73c824285ab..6a08c148461 100644
--- a/src/compiletest/compiletest.rs
+++ b/src/compiletest/compiletest.rs
@@ -42,12 +42,16 @@ fn parse_config(args: ~[~str]) -> config {
           err(f) => fail getopts::fail_str(f)
         };
 
+    fn opt_path(m: getopts::matches, nm: ~str) -> Path {
+        Path(getopts::opt_str(m, nm))
+    }
+
     return {compile_lib_path: getopts::opt_str(matches, ~"compile-lib-path"),
          run_lib_path: getopts::opt_str(matches, ~"run-lib-path"),
-         rustc_path: getopts::opt_str(matches, ~"rustc-path"),
-         src_base: getopts::opt_str(matches, ~"src-base"),
-         build_base: getopts::opt_str(matches, ~"build-base"),
-         aux_base: getopts::opt_str(matches, ~"aux-base"),
+         rustc_path: opt_path(matches, ~"rustc-path"),
+         src_base: opt_path(matches, ~"src-base"),
+         build_base: opt_path(matches, ~"build-base"),
+         aux_base: opt_path(matches, ~"aux-base"),
          stage_id: getopts::opt_str(matches, ~"stage-id"),
          mode: str_mode(getopts::opt_str(matches, ~"mode")),
          run_ignored: getopts::opt_present(matches, ~"ignored"),
@@ -55,7 +59,9 @@ fn parse_config(args: ~[~str]) -> config {
              if vec::len(matches.free) > 0u {
                  option::some(matches.free[0])
              } else { option::none },
-         logfile: getopts::opt_maybe_str(matches, ~"logfile"),
+         logfile: option::map(getopts::opt_maybe_str(matches,
+                                                     ~"logfile"),
+                              |s| Path(s)),
          runtool: getopts::opt_maybe_str(matches, ~"runtool"),
          rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"),
          verbose: getopts::opt_present(matches, ~"verbose")};
@@ -66,9 +72,9 @@ fn log_config(config: config) {
     logv(c, fmt!("configuration:"));
     logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
     logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
-    logv(c, fmt!("rustc_path: %s", config.rustc_path));
-    logv(c, fmt!("src_base: %s", config.src_base));
-    logv(c, fmt!("build_base: %s", config.build_base));
+    logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
+    logv(c, fmt!("src_base: %s", config.src_base.to_str()));
+    logv(c, fmt!("build_base: %s", config.build_base.to_str()));
     logv(c, fmt!("stage_id: %s", config.stage_id));
     logv(c, fmt!("mode: %s", mode_str(config.mode)));
     logv(c, fmt!("run_ignored: %b", config.run_ignored));
@@ -122,18 +128,19 @@ fn test_opts(config: config) -> test::test_opts {
      run_ignored: config.run_ignored,
      logfile:
          match config.logfile {
-           option::some(s) => option::some(s),
+           option::some(s) => option::some(s.to_str()),
            option::none => option::none
          }
     }
 }
 
 fn make_tests(config: config) -> ~[test::test_desc] {
-    debug!("making tests from %s", config.src_base);
+    debug!("making tests from %s",
+           config.src_base.to_str());
     let mut tests = ~[];
-    for os::list_dir_path(config.src_base).each |file| {
-        let file = file;
-        debug!("inspecting file %s", file);
+    for os::list_dir_path(&config.src_base).each |file| {
+        let file = copy file;
+        debug!("inspecting file %s", file.to_str());
         if is_test(config, file) {
             vec::push(tests, make_test(config, file))
         }
@@ -141,7 +148,7 @@ fn make_tests(config: config) -> ~[test::test_desc] {
     return tests;
 }
 
-fn is_test(config: config, testfile: ~str) -> bool {
+fn is_test(config: config, testfile: &Path) -> bool {
     // Pretty-printer does not work with .rc files yet
     let valid_extensions =
         match config.mode {
@@ -149,7 +156,7 @@ fn is_test(config: config, testfile: ~str) -> bool {
           _ => ~[~".rc", ~".rs"]
         };
     let invalid_prefixes = ~[~".", ~"#", ~"~"];
-    let name = path::basename(testfile);
+    let name = option::get(testfile.filename());
 
     let mut valid = false;
 
@@ -164,7 +171,7 @@ fn is_test(config: config, testfile: ~str) -> bool {
     return valid;
 }
 
-fn make_test(config: config, testfile: ~str) ->
+fn make_test(config: config, testfile: &Path) ->
    test::test_desc {
     {
         name: make_test_name(config, testfile),
@@ -174,12 +181,13 @@ fn make_test(config: config, testfile: ~str) ->
     }
 }
 
-fn make_test_name(config: config, testfile: ~str) -> ~str {
-    fmt!("[%s] %s", mode_str(config.mode), testfile)
+fn make_test_name(config: config, testfile: &Path) -> ~str {
+    fmt!("[%s] %s", mode_str(config.mode), testfile.to_str())
 }
 
-fn make_test_closure(config: config, testfile: ~str) -> test::test_fn {
-    fn~() { runtest::run(config, copy testfile) }
+fn make_test_closure(config: config, testfile: &Path) -> test::test_fn {
+    let testfile = testfile.to_str();
+    fn~() { runtest::run(config, testfile) }
 }
 
 // Local Variables:
diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs
index 030e1d01ab0..9dde2f86f96 100644
--- a/src/compiletest/errors.rs
+++ b/src/compiletest/errors.rs
@@ -6,7 +6,7 @@ export expected_error;
 type expected_error = { line: uint, kind: ~str, msg: ~str };
 
 // Load any test directives embedded in the file
-fn load_errors(testfile: ~str) -> ~[expected_error] {
+fn load_errors(testfile: &Path) -> ~[expected_error] {
     let mut error_patterns = ~[];
     let rdr = result::get(io::file_reader(testfile));
     let mut line_num = 1u;
diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs
index efaa822d015..2905537d6a1 100644
--- a/src/compiletest/header.rs
+++ b/src/compiletest/header.rs
@@ -14,7 +14,7 @@ type test_props = {
     compile_flags: option<~str>,
     // If present, the name of a file that this test should match when
     // pretty-printed
-    pp_exact: option<~str>,
+    pp_exact: option<Path>,
     // Modules from aux directory that should be compiled
     aux_builds: ~[~str],
     // Environment settings to use during execution
@@ -22,7 +22,7 @@ type test_props = {
 };
 
 // Load any test directives embedded in the file
-fn load_props(testfile: ~str) -> test_props {
+fn load_props(testfile: &Path) -> test_props {
     let mut error_patterns = ~[];
     let mut aux_builds = ~[];
     let mut exec_env = ~[];
@@ -59,7 +59,7 @@ fn load_props(testfile: ~str) -> test_props {
     };
 }
 
-fn is_test_ignored(config: config, testfile: ~str) -> bool {
+fn is_test_ignored(config: config, testfile: &Path) -> bool {
     let mut found = false;
     for iter_header(testfile) |ln| {
         if parse_name_directive(ln, ~"xfail-test") { return true; }
@@ -74,7 +74,7 @@ fn is_test_ignored(config: config, testfile: ~str) -> bool {
     }
 }
 
-fn iter_header(testfile: ~str, it: fn(~str) -> bool) -> bool {
+fn iter_header(testfile: &Path, it: fn(~str) -> bool) -> bool {
     let rdr = result::get(io::file_reader(testfile));
     while !rdr.eof() {
         let ln = rdr.read_line();
@@ -114,12 +114,12 @@ fn parse_exec_env(line: ~str) -> option<(~str, ~str)> {
     }
 }
 
-fn parse_pp_exact(line: ~str, testfile: ~str) -> option<~str> {
+fn parse_pp_exact(line: ~str, testfile: &Path) -> option<Path> {
     match parse_name_value_directive(line, ~"pp-exact") {
-      option::some(s) => option::some(s),
+      option::some(s) => option::some(Path(s)),
       option::none => {
         if parse_name_directive(line, ~"pp-exact") {
-            option::some(path::basename(testfile))
+            option::some(testfile.file_path())
         } else {
             option::none
         }
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index 6498a7d8952..fa003646699 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -16,17 +16,18 @@ fn run(config: config, testfile: ~str) {
         // We're going to be dumping a lot of info. Start on a new line.
         io::stdout().write_str(~"\n\n");
     }
-    debug!("running %s", testfile);
-    let props = load_props(testfile);
+    let testfile = Path(testfile);
+    debug!("running %s", testfile.to_str());
+    let props = load_props(&testfile);
     match config.mode {
-      mode_compile_fail => run_cfail_test(config, props, testfile),
-      mode_run_fail => run_rfail_test(config, props, testfile),
-      mode_run_pass => run_rpass_test(config, props, testfile),
-      mode_pretty => run_pretty_test(config, props, testfile)
+      mode_compile_fail => run_cfail_test(config, props, &testfile),
+      mode_run_fail => run_rfail_test(config, props, &testfile),
+      mode_run_pass => run_rpass_test(config, props, &testfile),
+      mode_pretty => run_pretty_test(config, props, &testfile)
     }
 }
 
-fn run_cfail_test(config: config, props: test_props, testfile: ~str) {
+fn run_cfail_test(config: config, props: test_props, testfile: &Path) {
     let procres = compile_test(config, props, testfile);
 
     if procres.status == 0 {
@@ -46,7 +47,7 @@ fn run_cfail_test(config: config, props: test_props, testfile: ~str) {
     }
 }
 
-fn run_rfail_test(config: config, props: test_props, testfile: ~str) {
+fn run_rfail_test(config: config, props: test_props, testfile: &Path) {
     let mut procres = compile_test(config, props, testfile);
 
     if procres.status != 0 { fatal_procres(~"compilation failed!", procres); }
@@ -74,7 +75,7 @@ fn check_correct_failure_status(procres: procres) {
     }
 }
 
-fn run_rpass_test(config: config, props: test_props, testfile: ~str) {
+fn run_rpass_test(config: config, props: test_props, testfile: &Path) {
     let mut procres = compile_test(config, props, testfile);
 
     if procres.status != 0 { fatal_procres(~"compilation failed!", procres); }
@@ -84,7 +85,7 @@ fn run_rpass_test(config: config, props: test_props, testfile: ~str) {
     if procres.status != 0 { fatal_procres(~"test run failed!", procres); }
 }
 
-fn run_pretty_test(config: config, props: test_props, testfile: ~str) {
+fn run_pretty_test(config: config, props: test_props, testfile: &Path) {
     if option::is_some(props.pp_exact) {
         logv(config, ~"testing for exact pretty-printing");
     } else { logv(config, ~"testing for converging pretty-printing"); }
@@ -111,8 +112,8 @@ fn run_pretty_test(config: config, props: test_props, testfile: ~str) {
     let mut expected =
         match props.pp_exact {
           option::some(file) => {
-            let filepath = path::connect(path::dirname(testfile), file);
-            result::get(io::read_whole_file_str(filepath))
+            let filepath = testfile.dir_path().push_rel(&file);
+            result::get(io::read_whole_file_str(&filepath))
           }
           option::none => { srcs[vec::len(srcs) - 2u] }
         };
@@ -136,15 +137,15 @@ fn run_pretty_test(config: config, props: test_props, testfile: ~str) {
 
     return;
 
-    fn print_source(config: config, testfile: ~str, src: ~str) -> procres {
+    fn print_source(config: config, testfile: &Path, src: ~str) -> procres {
         compose_and_run(config, testfile, make_pp_args(config, testfile),
                         ~[], config.compile_lib_path, option::some(src))
     }
 
-    fn make_pp_args(config: config, _testfile: ~str) -> procargs {
+    fn make_pp_args(config: config, _testfile: &Path) -> procargs {
         let prog = config.rustc_path;
         let args = ~[~"-", ~"--pretty", ~"normal"];
-        return {prog: prog, args: args};
+        return {prog: prog.to_str(), args: args};
     }
 
     fn compare_source(expected: ~str, actual: ~str) {
@@ -168,28 +169,30 @@ actual:\n\
     }
 
     fn typecheck_source(config: config, props: test_props,
-                        testfile: ~str, src: ~str) -> procres {
+                        testfile: &Path, src: ~str) -> procres {
         compose_and_run_compiler(
             config, props, testfile,
             make_typecheck_args(config, testfile),
             option::some(src))
     }
 
-    fn make_typecheck_args(config: config, testfile: ~str) -> procargs {
+    fn make_typecheck_args(config: config, testfile: &Path) -> procargs {
         let prog = config.rustc_path;
         let mut args = ~[~"-",
-                         ~"--no-trans", ~"--lib", ~"-L", config.build_base,
-                         ~"-L", aux_output_dir_name(config, testfile)];
+                         ~"--no-trans", ~"--lib",
+                         ~"-L", config.build_base.to_str(),
+                         ~"-L",
+                         aux_output_dir_name(config, testfile).to_str()];
         args += split_maybe_args(config.rustcflags);
-        return {prog: prog, args: args};
+        return {prog: prog.to_str(), args: args};
     }
 }
 
 fn check_error_patterns(props: test_props,
-                        testfile: ~str,
+                        testfile: &Path,
                         procres: procres) {
     if vec::is_empty(props.error_patterns) {
-        fatal(~"no error pattern specified in " + testfile);
+        fatal(~"no error pattern specified in " + testfile.to_str());
     }
 
     if procres.status == 0 {
@@ -228,7 +231,7 @@ fn check_error_patterns(props: test_props,
 }
 
 fn check_expected_errors(expected_errors: ~[errors::expected_error],
-                         testfile: ~str,
+                         testfile: &Path,
                          procres: procres) {
 
     // true if we found the error in question
@@ -240,7 +243,7 @@ fn check_expected_errors(expected_errors: ~[errors::expected_error],
     }
 
     let prefixes = vec::map(expected_errors, |ee| {
-        fmt!("%s:%u:", testfile, ee.line)
+        fmt!("%s:%u:", testfile.to_str(), ee.line)
     });
 
     // Scan and extract our error/warning messages,
@@ -291,8 +294,8 @@ type procargs = {prog: ~str, args: ~[~str]};
 type procres = {status: int, stdout: ~str, stderr: ~str, cmdline: ~str};
 
 fn compile_test(config: config, props: test_props,
-                testfile: ~str) -> procres {
-    let link_args = ~[~"-L", aux_output_dir_name(config, testfile)];
+                testfile: &Path) -> procres {
+    let link_args = ~[~"-L", aux_output_dir_name(config, testfile).to_str()];
     compose_and_run_compiler(
         config, props, testfile,
         make_compile_args(config, props, link_args,
@@ -301,7 +304,7 @@ fn compile_test(config: config, props: test_props,
 }
 
 fn exec_compiled_test(config: config, props: test_props,
-                      testfile: ~str) -> procres {
+                      testfile: &Path) -> procres {
     compose_and_run(config, testfile,
                     make_run_args(config, props, testfile),
                     props.exec_env,
@@ -311,26 +314,28 @@ fn exec_compiled_test(config: config, props: test_props,
 fn compose_and_run_compiler(
     config: config,
     props: test_props,
-    testfile: ~str,
+    testfile: &Path,
     args: procargs,
     input: option<~str>) -> procres {
 
     if props.aux_builds.is_not_empty() {
-        ensure_dir(aux_output_dir_name(config, testfile));
+        ensure_dir(&aux_output_dir_name(config, testfile));
     }
 
-    let extra_link_args = ~[~"-L", aux_output_dir_name(config, testfile)];
+    let extra_link_args = ~[~"-L",
+                            aux_output_dir_name(config, testfile).to_str()];
 
     do vec::iter(props.aux_builds) |rel_ab| {
-        let abs_ab = path::connect(config.aux_base, rel_ab);
+        let abs_ab = config.aux_base.push_rel(&Path(rel_ab));
         let aux_args =
             make_compile_args(config, props, ~[~"--lib"] + extra_link_args,
-                              |a,b| make_lib_name(a, b, testfile), abs_ab);
-        let auxres = compose_and_run(config, abs_ab, aux_args, ~[],
+                              |a,b| make_lib_name(a, b, testfile), &abs_ab);
+        let auxres = compose_and_run(config, &abs_ab, aux_args, ~[],
                                      config.compile_lib_path, option::none);
         if auxres.status != 0 {
             fatal_procres(
-                fmt!("auxiliary build of %s failed to compile: ", abs_ab),
+                fmt!("auxiliary build of %s failed to compile: ",
+                     abs_ab.to_str()),
                 auxres);
         }
     }
@@ -339,14 +344,14 @@ fn compose_and_run_compiler(
                     config.compile_lib_path, input)
 }
 
-fn ensure_dir(path: Path) {
+fn ensure_dir(path: &Path) {
     if os::path_is_dir(path) { return; }
     if !os::make_dir(path, 0x1c0i32) {
-        fail fmt!("can't make dir %s", path);
+        fail fmt!("can't make dir %s", path.to_str());
     }
 }
 
-fn compose_and_run(config: config, testfile: ~str,
+fn compose_and_run(config: config, testfile: &Path,
                    procargs: procargs,
                    procenv: ~[(~str, ~str)],
                    lib_path: ~str,
@@ -356,28 +361,30 @@ fn compose_and_run(config: config, testfile: ~str,
 }
 
 fn make_compile_args(config: config, props: test_props, extras: ~[~str],
-                     xform: fn(config, ~str) -> ~str, testfile: ~str) ->
-   procargs {
+                     xform: fn(config, (&Path)) -> Path,
+                     testfile: &Path) -> procargs {
     let prog = config.rustc_path;
-    let mut args = ~[testfile, ~"-o", xform(config, testfile),
-                    ~"-L", config.build_base] + extras;
+    let mut args = ~[testfile.to_str(),
+                     ~"-o", xform(config, testfile).to_str(),
+                     ~"-L", config.build_base.to_str()]
+        + extras;
     args += split_maybe_args(config.rustcflags);
     args += split_maybe_args(props.compile_flags);
-    return {prog: prog, args: args};
+    return {prog: prog.to_str(), args: args};
 }
 
-fn make_lib_name(config: config, auxfile: ~str, testfile: ~str) -> ~str {
+fn make_lib_name(config: config, auxfile: &Path, testfile: &Path) -> Path {
     // what we return here is not particularly important, as it
     // happens; rustc ignores everything except for the directory.
     let auxname = output_testname(auxfile);
-    path::connect(aux_output_dir_name(config, testfile), auxname)
+    aux_output_dir_name(config, testfile).push_rel(&auxname)
 }
 
-fn make_exe_name(config: config, testfile: ~str) -> ~str {
-    output_base_name(config, testfile) + os::exe_suffix()
+fn make_exe_name(config: config, testfile: &Path) -> Path {
+    Path(output_base_name(config, testfile).to_str() + os::exe_suffix())
 }
 
-fn make_run_args(config: config, _props: test_props, testfile: ~str) ->
+fn make_run_args(config: config, _props: test_props, testfile: &Path) ->
    procargs {
     let toolargs = {
             // If we've got another tool to run under (valgrind),
@@ -390,7 +397,7 @@ fn make_run_args(config: config, _props: test_props, testfile: ~str) ->
             split_maybe_args(runtool)
         };
 
-    let args = toolargs + ~[make_exe_name(config, testfile)];
+    let args = toolargs + ~[make_exe_name(config, testfile).to_str()];
     return {prog: args[0], args: vec::slice(args, 1u, vec::len(args))};
 }
 
@@ -408,7 +415,7 @@ fn split_maybe_args(argstr: option<~str>) -> ~[~str] {
     }
 }
 
-fn program_output(config: config, testfile: ~str, lib_path: ~str, prog: ~str,
+fn program_output(config: config, testfile: &Path, lib_path: ~str, prog: ~str,
                   args: ~[~str], env: ~[(~str, ~str)],
                   input: option<~str>) -> procres {
     let cmdline =
@@ -445,37 +452,36 @@ fn lib_path_cmd_prefix(path: ~str) -> ~str {
     fmt!("%s=\"%s\"", util::lib_path_env_var(), util::make_new_path(path))
 }
 
-fn dump_output(config: config, testfile: ~str, out: ~str, err: ~str) {
+fn dump_output(config: config, testfile: &Path, out: ~str, err: ~str) {
     dump_output_file(config, testfile, out, ~"out");
     dump_output_file(config, testfile, err, ~"err");
     maybe_dump_to_stdout(config, out, err);
 }
 
-fn dump_output_file(config: config, testfile: ~str,
+fn dump_output_file(config: config, testfile: &Path,
                     out: ~str, extension: ~str) {
     let outfile = make_out_name(config, testfile, extension);
     let writer = result::get(
-        io::file_writer(outfile, ~[io::Create, io::Truncate]));
+        io::file_writer(&outfile, ~[io::Create, io::Truncate]));
     writer.write_str(out);
 }
 
-fn make_out_name(config: config, testfile: ~str, extension: ~str) -> ~str {
-    output_base_name(config, testfile) + ~"." + extension
+fn make_out_name(config: config, testfile: &Path, extension: ~str) -> Path {
+    output_base_name(config, testfile).with_filetype(extension)
 }
 
-fn aux_output_dir_name(config: config, testfile: ~str) -> ~str {
-    output_base_name(config, testfile) + ~".libaux"
+fn aux_output_dir_name(config: config, testfile: &Path) -> Path {
+    output_base_name(config, testfile).with_filetype("libaux")
 }
 
-fn output_testname(testfile: ~str) -> ~str {
-    let parts = str::split_char(path::basename(testfile), '.');
-    str::connect(vec::slice(parts, 0u, vec::len(parts) - 1u), ~".")
+fn output_testname(testfile: &Path) -> Path {
+    Path(option::get(testfile.filestem()))
 }
 
-fn output_base_name(config: config, testfile: ~str) -> ~str {
-    let base = config.build_base;
-    let filename = output_testname(testfile);
-    fmt!("%s%s.%s", base, filename, config.stage_id)
+fn output_base_name(config: config, testfile: &Path) -> Path {
+    config.build_base
+        .push_rel(&output_testname(testfile))
+        .with_filetype(config.stage_id)
 }
 
 fn maybe_dump_to_stdout(config: config, out: ~str, err: ~str) {
diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs
index 5d04ab8bf1a..7f496acda8f 100644
--- a/src/fuzzer/fuzzer.rs
+++ b/src/fuzzer/fuzzer.rs
@@ -8,7 +8,7 @@ import syntax::diagnostic;
 enum test_mode { tm_converge, tm_run, }
 type context = { mode: test_mode }; // + rng
 
-fn write_file(filename: ~str, content: ~str) {
+fn write_file(filename: &Path, content: ~str) {
     result::get(
         io::file_writer(filename, ~[io::Create, io::Truncate]))
         .write_str(content);
@@ -18,13 +18,13 @@ fn contains(haystack: ~str, needle: ~str) -> bool {
     str::contains(haystack, needle)
 }
 
-fn find_rust_files(&files: ~[~str], path: ~str) {
-    if str::ends_with(path, ~".rs") && !contains(path, ~"utf8") {
+fn find_rust_files(files: &mut ~[Path], path: &Path) {
+    if path.filetype() == some(~"rs") && !contains(path.to_str(), ~"utf8") {
         // ignoring "utf8" tests because something is broken
-        files += ~[path];
+        vec::push(*files, *path);
     } else if os::path_is_dir(path)
-        && !contains(path, ~"compile-fail")
-        && !contains(path, ~"build") {
+        && !contains(path.to_str(), ~"compile-fail")
+        && !contains(path.to_str(), ~"build") {
         for os::list_dir_path(path).each |p| {
             find_rust_files(files, p);
         }
@@ -221,7 +221,7 @@ fn as_str(f: fn@(io::Writer)) -> ~str {
 }
 
 fn check_variants_of_ast(crate: ast::crate, codemap: codemap::codemap,
-                         filename: ~str, cx: context) {
+                         filename: &Path, cx: context) {
     let stolen = steal(crate, cx.mode);
     let extra_exprs = vec::filter(common_exprs(),
                                   |a| safe_to_use_expr(a, cx.mode) );
@@ -235,14 +235,14 @@ fn check_variants_of_ast(crate: ast::crate, codemap: codemap::codemap,
 fn check_variants_T<T: copy>(
   crate: ast::crate,
   codemap: codemap::codemap,
-  filename: ~str,
+  filename: &Path,
   thing_label: ~str,
   things: ~[T],
   stringifier: fn@(@T, syntax::parse::token::ident_interner) -> ~str,
   replacer: fn@(ast::crate, uint, T, test_mode) -> ast::crate,
   cx: context
   ) {
-    error!("%s contains %u %s objects", filename,
+    error!("%s contains %u %s objects", filename.to_str(),
            vec::len(things), thing_label);
 
     // Assuming we're not generating any token_trees
@@ -253,6 +253,7 @@ fn check_variants_T<T: copy>(
     if L < 100u {
         do under(uint::min(L, 20u)) |i| {
             log(error, ~"Replacing... #" + uint::str(i));
+            let fname = str::from_slice(filename.to_str());
             do under(uint::min(L, 30u)) |j| {
                 log(error, ~"With... " + stringifier(@things[j], intr));
                 let crate2 = @replacer(crate, i, things[j], cx.mode);
@@ -265,7 +266,7 @@ fn check_variants_T<T: copy>(
                         intr,
                         diagnostic::mk_span_handler(handler, codemap),
                         crate2,
-                        filename,
+                        fname,
                         rdr, a,
                         pprust::no_ann(),
                         false))
@@ -276,11 +277,12 @@ fn check_variants_T<T: copy>(
                   }
                   tm_run => {
                     let file_label = fmt!("rusttmp/%s_%s_%u_%u",
-                                          last_part(filename),
+                                          last_part(filename.to_str()),
                                           thing_label, i, j);
                     let safe_to_run = !(content_is_dangerous_to_run(*str3)
                                         || has_raw_pointers(*crate2));
-                    check_whole_compiler(*str3, file_label, safe_to_run);
+                    check_whole_compiler(*str3, &Path(file_label),
+                                         safe_to_run);
                   }
                 }
             }
@@ -305,9 +307,9 @@ enum happiness {
 // - that would be tricky, requiring use of tasks or serialization
 //   or randomness.
 // This seems to find plenty of bugs as it is :)
-fn check_whole_compiler(code: ~str, suggested_filename_prefix: ~str,
+fn check_whole_compiler(code: ~str, suggested_filename_prefix: &Path,
                         allow_running: bool) {
-    let filename = suggested_filename_prefix + ~".rs";
+    let filename = &suggested_filename_prefix.with_filetype("rs");
     write_file(filename, code);
 
     let compile_result = check_compiling(filename);
@@ -320,32 +322,32 @@ fn check_whole_compiler(code: ~str, suggested_filename_prefix: ~str,
     match run_result {
       passed | cleanly_rejected(_) | known_bug(_) => {
         removeIfExists(suggested_filename_prefix);
-        removeIfExists(suggested_filename_prefix + ~".rs");
-        removeDirIfExists(suggested_filename_prefix + ~".dSYM");
+        removeIfExists(&suggested_filename_prefix.with_filetype("rs"));
+        removeDirIfExists(&suggested_filename_prefix.with_filetype("dSYM"));
       }
       failed(s) => {
         log(error, ~"check_whole_compiler failure: " + s);
-        log(error, ~"Saved as: " + filename);
+        log(error, ~"Saved as: " + filename.to_str());
       }
     }
 }
 
-fn removeIfExists(filename: ~str) {
+fn removeIfExists(filename: &Path) {
     // So sketchy!
-    assert !contains(filename, ~" ");
-    run::program_output(~"bash", ~[~"-c", ~"rm " + filename]);
+    assert !contains(filename.to_str(), ~" ");
+    run::program_output(~"bash", ~[~"-c", ~"rm " + filename.to_str()]);
 }
 
-fn removeDirIfExists(filename: ~str) {
+fn removeDirIfExists(filename: &Path) {
     // So sketchy!
-    assert !contains(filename, ~" ");
-    run::program_output(~"bash", ~[~"-c", ~"rm -r " + filename]);
+    assert !contains(filename.to_str(), ~" ");
+    run::program_output(~"bash", ~[~"-c", ~"rm -r " + filename.to_str()]);
 }
 
-fn check_running(exe_filename: ~str) -> happiness {
+fn check_running(exe_filename: &Path) -> happiness {
     let p = run::program_output(
         ~"/Users/jruderman/scripts/timed_run_rust_program.py",
-        ~[exe_filename]);
+        ~[exe_filename.to_str()]);
     let comb = p.out + ~"\n" + p.err;
     if str::len(comb) > 1u {
         log(error, ~"comb comb comb: " + comb);
@@ -381,11 +383,11 @@ fn check_running(exe_filename: ~str) -> happiness {
     }
 }
 
-fn check_compiling(filename: ~str) -> happiness {
+fn check_compiling(filename: &Path) -> happiness {
     let p = run::program_output(
         ~"/Users/jruderman/code/rust/build/x86_64-apple-darwin/\
          stage1/bin/rustc",
-        ~[filename]);
+        ~[filename.to_str()]);
 
     //error!("Status: %d", p.status);
     if p.status == 0 {
@@ -415,11 +417,11 @@ fn check_compiling(filename: ~str) -> happiness {
 
 
 fn parse_and_print(code: @~str) -> ~str {
-    let filename = ~"tmp.rs";
+    let filename = Path("tmp.rs");
     let sess = parse::new_parse_sess(option::none);
-    write_file(filename, *code);
+    write_file(&filename, *code);
     let crate = parse::parse_crate_from_source_str(
-        filename, code, ~[], sess);
+        filename.to_str(), code, ~[], sess);
     do io::with_str_reader(*code) |rdr| {
         as_str(|a|
                pprust::print_crate(
@@ -428,7 +430,7 @@ fn parse_and_print(code: @~str) -> ~str {
                    syntax::parse::token::mk_fake_ident_interner(),
                    sess.span_diagnostic,
                    crate,
-                   filename,
+                   filename.to_str(),
                    rdr, a,
                    pprust::no_ann(),
                    false) )
@@ -486,7 +488,7 @@ fn content_might_not_converge(code: ~str) -> bool {
     return false;
 }
 
-fn file_might_not_converge(filename: ~str) -> bool {
+fn file_might_not_converge(filename: &Path) -> bool {
     let confusing_files = ~[
       ~"expr-alt.rs", // pretty-printing "(a = b) = c"
                      // vs "a = b = c" and wrapping
@@ -496,7 +498,11 @@ fn file_might_not_converge(filename: ~str) -> bool {
     ];
 
 
-    for confusing_files.each |f| { if contains(filename, f) { return true; } }
+    for confusing_files.each |f| {
+        if contains(filename.to_str(), f) {
+            return true;
+        }
+    }
 
     return false;
 }
@@ -519,8 +525,8 @@ fn check_roundtrip_convergence(code: @~str, maxIters: uint) {
         error!("Converged after %u iterations", i);
     } else {
         error!("Did not converge after %u iterations!", i);
-        write_file(~"round-trip-a.rs", *oldv);
-        write_file(~"round-trip-b.rs", *newv);
+        write_file(&Path("round-trip-a.rs"), *oldv);
+        write_file(&Path("round-trip-b.rs"), *newv);
         run::run_program(~"diff",
                          ~[~"-w", ~"-u", ~"round-trip-a.rs",
                           ~"round-trip-b.rs"]);
@@ -528,13 +534,13 @@ fn check_roundtrip_convergence(code: @~str, maxIters: uint) {
     }
 }
 
-fn check_convergence(files: ~[~str]) {
+fn check_convergence(files: &[Path]) {
     error!("pp convergence tests: %u files", vec::len(files));
     for files.each |file| {
-        if !file_might_not_converge(file) {
-            let s = @result::get(io::read_whole_file_str(file));
+        if !file_might_not_converge(&file) {
+            let s = @result::get(io::read_whole_file_str(&file));
             if !content_might_not_converge(*s) {
-                error!("pp converge: %s", file);
+                error!("pp converge: %s", file.to_str());
                 // Change from 7u to 2u once
                 // https://github.com/mozilla/rust/issues/850 is fixed
                 check_roundtrip_convergence(s, 7u);
@@ -543,15 +549,16 @@ fn check_convergence(files: ~[~str]) {
     }
 }
 
-fn check_variants(files: ~[~str], cx: context) {
+fn check_variants(files: &[Path], cx: context) {
     for files.each |file| {
-        if cx.mode == tm_converge && file_might_not_converge(file) {
+        if cx.mode == tm_converge &&
+            file_might_not_converge(&file) {
             error!("Skipping convergence test based on\
                     file_might_not_converge");
             again;
         }
 
-        let s = @result::get(io::read_whole_file_str(file));
+        let s = @result::get(io::read_whole_file_str(&file));
         if contains(*s, ~"#") {
             again; // Macros are confusing
         }
@@ -562,11 +569,11 @@ fn check_variants(files: ~[~str], cx: context) {
             again;
         }
 
-        log(error, ~"check_variants: " + file);
+        log(error, ~"check_variants: " + file.to_str());
         let sess = parse::new_parse_sess(option::none);
         let crate =
             parse::parse_crate_from_source_str(
-                file,
+                file.to_str(),
                 s, ~[], sess);
         io::with_str_reader(*s, |rdr| {
             error!("%s",
@@ -576,12 +583,12 @@ fn check_variants(files: ~[~str], cx: context) {
                        syntax::parse::token::mk_fake_ident_interner(),
                        sess.span_diagnostic,
                        crate,
-                       file,
+                       file.to_str(),
                        rdr, a,
                        pprust::no_ann(),
                        false) ))
         });
-        check_variants_of_ast(*crate, sess.cm, file, cx);
+        check_variants_of_ast(*crate, sess.cm, &file, cx);
     }
 }
 
@@ -591,9 +598,9 @@ fn main(args: ~[~str]) {
         return;
     }
     let mut files = ~[];
-    let root = args[1];
+    let root = Path(args[1]);
 
-    find_rust_files(files, root);
+    find_rust_files(&mut files, &root);
     error!("== check_convergence ==");
     check_convergence(files);
     error!("== check_variants: converge ==");
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index 4b1ace5651b..84c0568797c 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -54,7 +54,7 @@ export send_map;
 export hash;
 export cmp;
 export num;
-export path;
+export path, path2;
 export managed;
 
 // NDM seems to be necessary for resolve to work
diff --git a/src/libcore/core.rs b/src/libcore/core.rs
index 2f7ae426517..c95a42ea3ec 100644
--- a/src/libcore/core.rs
+++ b/src/libcore/core.rs
@@ -4,7 +4,12 @@
 
 import option::{some, none};
 import option = option::option;
-import Path = path::Path;
+
+import Path = path2::Path;
+import GenericPath = path2::GenericPath;
+import WindowsPath = path2::WindowsPath;
+import PosixPath = path2::PosixPath;
+
 import tuple::{TupleOps, ExtendedTupleOps};
 import str::{StrSlice, UniqueStr};
 import vec::{ConstVector, CopyableVector, ImmutableVector};
@@ -14,7 +19,8 @@ import num::Num;
 import ptr::Ptr;
 import to_str::ToStr;
 
-export Path, option, some, none, unreachable;
+export Path, WindowsPath, PosixPath, GenericPath;
+export option, some, none, unreachable;
 export extensions;
 // The following exports are the extension impls for numeric types
 export Num, Times, TimesIx;
diff --git a/src/libcore/io.rs b/src/libcore/io.rs
index a2b02f55b22..452aae49984 100644
--- a/src/libcore/io.rs
+++ b/src/libcore/io.rs
@@ -257,13 +257,14 @@ fn FILE_reader(f: *libc::FILE, cleanup: bool) -> Reader {
 
 fn stdin() -> Reader { rustrt::rust_get_stdin() as Reader }
 
-fn file_reader(path: ~str) -> result<Reader, ~str> {
-    let f = os::as_c_charp(path, |pathbuf| {
-        os::as_c_charp(~"r", |modebuf|
+fn file_reader(path: &Path) -> result<Reader, ~str> {
+    let f = os::as_c_charp(path.to_str(), |pathbuf| {
+        os::as_c_charp("r", |modebuf|
             libc::fopen(pathbuf, modebuf)
         )
     });
-    return if f as uint == 0u { result::err(~"error opening " + path) }
+    return if f as uint == 0u { result::err(~"error opening "
+                                            + path.to_str()) }
     else {
         result::ok(FILE_reader(f, true))
     }
@@ -412,7 +413,7 @@ fn fd_writer(fd: fd_t, cleanup: bool) -> Writer {
 }
 
 
-fn mk_file_writer(path: ~str, flags: ~[FileFlag])
+fn mk_file_writer(path: &Path, flags: ~[FileFlag])
     -> result<Writer, ~str> {
 
     #[cfg(windows)]
@@ -430,12 +431,13 @@ fn mk_file_writer(path: ~str, flags: ~[FileFlag])
           NoFlag => ()
         }
     }
-    let fd = do os::as_c_charp(path) |pathbuf| {
+    let fd = do os::as_c_charp(path.to_str()) |pathbuf| {
         libc::open(pathbuf, fflags,
                    (S_IRUSR | S_IWUSR) as c_int)
     };
     if fd < (0 as c_int) {
-        result::err(fmt!("error opening %s: %s", path, os::last_os_error()))
+        result::err(fmt!("error opening %s: %s", path.to_str(),
+                         os::last_os_error()))
     } else {
         result::ok(fd_writer(fd, true))
     }
@@ -614,19 +616,20 @@ impl<T: Writer> T : WriterUtil {
     fn write_u8(n: u8) { self.write(&[n]) }
 }
 
-fn file_writer(path: ~str, flags: ~[FileFlag]) -> result<Writer, ~str> {
+fn file_writer(path: &Path, flags: ~[FileFlag]) -> result<Writer, ~str> {
     result::chain(mk_file_writer(path, flags), |w| result::ok(w))
 }
 
 
 // FIXME: fileflags // #2004
-fn buffered_file_writer(path: ~str) -> result<Writer, ~str> {
-    let f = do os::as_c_charp(path) |pathbuf| {
-        do os::as_c_charp(~"w") |modebuf| {
+fn buffered_file_writer(path: &Path) -> result<Writer, ~str> {
+    let f = do os::as_c_charp(path.to_str()) |pathbuf| {
+        do os::as_c_charp("w") |modebuf| {
             libc::fopen(pathbuf, modebuf)
         }
     };
-    return if f as uint == 0u { result::err(~"error opening " + path) }
+    return if f as uint == 0u { result::err(~"error opening "
+                                            + path.to_str()) }
     else { result::ok(FILE_writer(f, true)) }
 }
 
@@ -709,19 +712,19 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
     return bpos as uint;
 }
 
-fn read_whole_file_str(file: ~str) -> result<~str, ~str> {
+fn read_whole_file_str(file: &Path) -> result<~str, ~str> {
     result::chain(read_whole_file(file), |bytes| {
         if str::is_utf8(bytes) {
             result::ok(str::from_bytes(bytes))
        } else {
-           result::err(file + ~" is not UTF-8")
+           result::err(file.to_str() + ~" is not UTF-8")
        }
     })
 }
 
 // FIXME (#2004): implement this in a low-level way. Going through the
 // abstractions is pointless.
-fn read_whole_file(file: ~str) -> result<~[u8], ~str> {
+fn read_whole_file(file: &Path) -> result<~[u8], ~str> {
     result::chain(file_reader(file), |rdr| {
         result::ok(rdr.read_whole_stream())
     })
@@ -810,7 +813,7 @@ mod tests {
 
     #[test]
     fn test_simple() {
-        let tmpfile: ~str = ~"tmp/lib-io-test-simple.tmp";
+        let tmpfile = &Path("tmp/lib-io-test-simple.tmp");
         log(debug, tmpfile);
         let frood: ~str =
             ~"A hoopy frood who really knows where his towel is.";
@@ -881,7 +884,7 @@ mod tests {
 
     #[test]
     fn file_reader_not_exist() {
-        match io::file_reader(~"not a file") {
+        match io::file_reader(&Path("not a file")) {
           result::err(e) => {
             assert e == ~"error opening not a file";
           }
@@ -891,9 +894,9 @@ mod tests {
 
     #[test]
     fn file_writer_bad_name() {
-        match io::file_writer(~"?/?", ~[]) {
+        match io::file_writer(&Path("?/?"), ~[]) {
           result::err(e) => {
-            assert str::starts_with(e, ~"error opening ?/?");
+            assert str::starts_with(e, "error opening");
           }
           result::ok(_) => fail
         }
@@ -901,9 +904,9 @@ mod tests {
 
     #[test]
     fn buffered_file_writer_bad_name() {
-        match io::buffered_file_writer(~"?/?") {
+        match io::buffered_file_writer(&Path("?/?")) {
           result::err(e) => {
-            assert e == ~"error opening ?/?";
+            assert str::starts_with(e, "error opening");
           }
           result::ok(_) => fail
         }
diff --git a/src/libcore/os.rs b/src/libcore/os.rs
index 749cb246af2..4fb3e744235 100644
--- a/src/libcore/os.rs
+++ b/src/libcore/os.rs
@@ -1,3 +1,7 @@
+// NB: transitionary, de-mode-ing.
+#[forbid(deprecated_mode)];
+#[forbid(deprecated_pattern)];
+
 /*!
  * Higher-level interfaces to libc::* functions and operating system services.
  *
@@ -16,16 +20,12 @@
  * to write OS-ignorant code by default.
  */
 
-#[forbid(deprecated_mode)];
-#[forbid(deprecated_pattern)];
-
 import libc::{c_char, c_void, c_int, c_uint, size_t, ssize_t,
               mode_t, pid_t, FILE};
 import libc::{close, fclose};
 
 import option::{some, none};
 
-import getcwd = rustrt::rust_getcwd;
 import consts::*;
 import task::TaskBuilder;
 
@@ -56,7 +56,11 @@ extern mod rustrt {
 
 const tmpbuf_sz : uint = 1000u;
 
-fn as_c_charp<T>(+s: ~str, f: fn(*c_char) -> T) -> T {
+fn getcwd() -> Path {
+    Path(rustrt::rust_getcwd())
+}
+
+fn as_c_charp<T>(s: &str, f: fn(*c_char) -> T) -> T {
     str::as_c_str(s, |b| f(b as *c_char))
 }
 
@@ -106,7 +110,7 @@ mod win32 {
         return res;
     }
 
-    fn as_utf16_p<T>(+s: ~str, f: fn(*u16) -> T) -> T {
+    fn as_utf16_p<T>(s: &str, f: fn(*u16) -> T) -> T {
         let mut t = str::to_utf16(s);
         // Null terminate before passing on.
         t += ~[0u16];
@@ -114,11 +118,11 @@ mod win32 {
     }
 }
 
-fn getenv(+n: ~str) -> option<~str> {
+fn getenv(n: &str) -> option<~str> {
     global_env::getenv(n)
 }
 
-fn setenv(+n: ~str, +v: ~str) {
+fn setenv(n: &str, v: &str) {
     global_env::setenv(n, v)
 }
 
@@ -143,17 +147,20 @@ mod global_env {
         MsgEnv(comm::Chan<~[(~str,~str)]>)
     }
 
-    fn getenv(+n: ~str) -> option<~str> {
+    fn getenv(n: &str) -> option<~str> {
         let env_ch = get_global_env_chan();
         let po = comm::port();
-        comm::send(env_ch, MsgGetEnv(n, comm::chan(po)));
+        comm::send(env_ch, MsgGetEnv(str::from_slice(n),
+                                     comm::chan(po)));
         comm::recv(po)
     }
 
-    fn setenv(+n: ~str, +v: ~str) {
+    fn setenv(n: &str, v: &str) {
         let env_ch = get_global_env_chan();
         let po = comm::port();
-        comm::send(env_ch, MsgSetEnv(n, v, comm::chan(po)));
+        comm::send(env_ch, MsgSetEnv(str::from_slice(n),
+                                     str::from_slice(v),
+                                     comm::chan(po)));
         comm::recv(po)
     }
 
@@ -212,7 +219,7 @@ mod global_env {
         }
 
         #[cfg(unix)]
-        fn getenv(+n: ~str) -> option<~str> {
+        fn getenv(n: &str) -> option<~str> {
             unsafe {
                 let s = str::as_c_str(n, libc::getenv);
                 return if unsafe::reinterpret_cast(s) == 0 {
@@ -225,7 +232,7 @@ mod global_env {
         }
 
         #[cfg(windows)]
-        fn getenv(+n: ~str) -> option<~str> {
+        fn getenv(n: &str) -> option<~str> {
             import libc::types::os::arch::extra::*;
             import libc::funcs::extra::kernel32::*;
             import win32::*;
@@ -238,7 +245,7 @@ mod global_env {
 
 
         #[cfg(unix)]
-        fn setenv(+n: ~str, +v: ~str) {
+        fn setenv(n: &str, v: &str) {
 
             // FIXME: remove this when export globs work properly. #1238
             import libc::funcs::posix01::unistd::setenv;
@@ -251,7 +258,7 @@ mod global_env {
 
 
         #[cfg(windows)]
-        fn setenv(+n: ~str, +v: ~str) {
+        fn setenv(n: &str, v: &str) {
             // FIXME: remove imports when export globs work properly. #1238
             import libc::funcs::extra::kernel32::*;
             import win32::*;
@@ -266,7 +273,7 @@ mod global_env {
 }
 
 fn fdopen(fd: c_int) -> *FILE {
-    return do as_c_charp(~"r") |modebuf| {
+    return do as_c_charp("r") |modebuf| {
         libc::fdopen(fd, modebuf)
     };
 }
@@ -365,8 +372,8 @@ fn dup2(src: c_int, dst: c_int) -> c_int {
 }
 
 
-fn dll_filename(+base: ~str) -> ~str {
-    return pre() + base + dll_suffix();
+fn dll_filename(base: &str) -> ~str {
+    return pre() + str::from_slice(base) + dll_suffix();
 
     #[cfg(unix)]
     fn pre() -> ~str { ~"lib" }
@@ -379,7 +386,7 @@ fn dll_filename(+base: ~str) -> ~str {
 fn self_exe_path() -> option<Path> {
 
     #[cfg(target_os = "freebsd")]
-    fn load_self() -> option<Path> {
+    fn load_self() -> option<~str> {
         unsafe {
             import libc::funcs::bsd44::*;
             import libc::consts::os::extra::*;
@@ -395,17 +402,17 @@ fn self_exe_path() -> option<Path> {
     }
 
     #[cfg(target_os = "linux")]
-    fn load_self() -> option<Path> {
+    fn load_self() -> option<~str> {
         import libc::funcs::posix01::unistd::readlink;
         do fill_charp_buf() |buf, sz| {
-            do as_c_charp(~"/proc/self/exe") |proc_self_buf| {
+            do as_c_charp("/proc/self/exe") |proc_self_buf| {
                 readlink(proc_self_buf, buf, sz) != (-1 as ssize_t)
             }
         }
     }
 
     #[cfg(target_os = "macos")]
-    fn load_self() -> option<Path> {
+    fn load_self() -> option<~str> {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::funcs::extra::*;
         do fill_charp_buf() |buf, sz| {
@@ -415,7 +422,7 @@ fn self_exe_path() -> option<Path> {
     }
 
     #[cfg(windows)]
-    fn load_self() -> option<Path> {
+    fn load_self() -> option<~str> {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::types::os::arch::extra::*;
         import libc::funcs::extra::kernel32::*;
@@ -426,7 +433,7 @@ fn self_exe_path() -> option<Path> {
     }
 
     do option::map(load_self()) |pth| {
-        path::dirname(pth) + path::path_sep()
+        Path(pth).dir_path()
     }
 }
 
@@ -447,7 +454,7 @@ fn self_exe_path() -> option<Path> {
 fn homedir() -> option<Path> {
     return match getenv(~"HOME") {
         some(p) => if !str::is_empty(p) {
-          some(p)
+          some(Path(p))
         } else {
           secondary()
         },
@@ -463,7 +470,7 @@ fn homedir() -> option<Path> {
     fn secondary() -> option<Path> {
         do option::chain(getenv(~"USERPROFILE")) |p| {
             if !str::is_empty(p) {
-                some(p)
+                some(Path(p))
             } else {
                 none
             }
@@ -484,13 +491,13 @@ fn homedir() -> option<Path> {
 fn tmpdir() -> Path {
     return lookup();
 
-    fn getenv_nonempty(+v: Path) -> option<Path> {
+    fn getenv_nonempty(v: &str) -> option<Path> {
         match getenv(v) {
             some(x) =>
                 if str::is_empty(x) {
                     none
                 } else {
-                    some(x)
+                    some(Path(x))
                 },
             _ => none
         }
@@ -498,28 +505,29 @@ fn tmpdir() -> Path {
 
     #[cfg(unix)]
     fn lookup() -> Path {
-        option::get_default(getenv_nonempty(~"TMPDIR"), ~"/tmp")
+        option::get_default(getenv_nonempty("TMPDIR"),
+                            Path("/tmp"))
     }
 
     #[cfg(windows)]
     fn lookup() -> Path {
         option::get_default(
-                    option::or(getenv_nonempty(~"TMP"),
-                    option::or(getenv_nonempty(~"TEMP"),
-                    option::or(getenv_nonempty(~"USERPROFILE"),
-                               getenv_nonempty(~"WINDIR")))),
-                    ~"C:\\Windows")
+                    option::or(getenv_nonempty("TMP"),
+                    option::or(getenv_nonempty("TEMP"),
+                    option::or(getenv_nonempty("USERPROFILE"),
+                               getenv_nonempty("WINDIR")))),
+                    Path("C:\\Windows"))
     }
 }
 /// Recursively walk a directory structure
-fn walk_dir(+p: Path, f: fn(Path) -> bool) {
+fn walk_dir(p: &Path, f: fn((&Path)) -> bool) {
 
     walk_dir_(p, f);
 
-    fn walk_dir_(+p: Path, f: fn(Path) -> bool) -> bool {
+    fn walk_dir_(p: &Path, f: fn((&Path)) -> bool) -> bool {
         let mut keepgoing = true;
         do list_dir(p).each |q| {
-            let path = path::connect(p, q);
+            let path = &p.push(q);
             if !f(path) {
                 keepgoing = false;
                 false
@@ -541,15 +549,15 @@ fn walk_dir(+p: Path, f: fn(Path) -> bool) {
 }
 
 /// Indicates whether a path represents a directory
-fn path_is_dir(+p: Path) -> bool {
-    do str::as_c_str(p) |buf| {
+fn path_is_dir(p: &Path) -> bool {
+    do str::as_c_str(p.to_str()) |buf| {
         rustrt::rust_path_is_dir(buf) != 0 as c_int
     }
 }
 
 /// Indicates whether a path exists
-fn path_exists(+p: Path) -> bool {
-    do str::as_c_str(p) |buf| {
+fn path_exists(p: &Path) -> bool {
+    do str::as_c_str(p.to_str()) |buf| {
         rustrt::rust_path_exists(buf) != 0 as c_int
     }
 }
@@ -566,58 +574,50 @@ fn path_exists(+p: Path) -> bool {
 // NB: this is here rather than in path because it is a form of environment
 // querying; what it does depends on the process working directory, not just
 // the input paths.
-fn make_absolute(+p: Path) -> Path {
-    if path::path_is_absolute(p) {
-        p
+fn make_absolute(p: &Path) -> Path {
+    if p.is_absolute {
+        copy *p
     } else {
-        path::connect(getcwd(), p)
+        getcwd().push_many(p.components)
     }
 }
 
 
 /// Creates a directory at the specified path
-fn make_dir(+p: Path, mode: c_int) -> bool {
+fn make_dir(p: &Path, mode: c_int) -> bool {
     return mkdir(p, mode);
 
     #[cfg(windows)]
-    fn mkdir(+p: Path, _mode: c_int) -> bool {
+    fn mkdir(p: &Path, _mode: c_int) -> bool {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::types::os::arch::extra::*;
         import libc::funcs::extra::kernel32::*;
         import win32::*;
         // FIXME: turn mode into something useful? #2623
-        do as_utf16_p(p) |buf| {
+        do as_utf16_p(p.to_str()) |buf| {
             CreateDirectoryW(buf, unsafe { unsafe::reinterpret_cast(0) })
                 != (0 as BOOL)
         }
     }
 
     #[cfg(unix)]
-    fn mkdir(+p: Path, mode: c_int) -> bool {
-        do as_c_charp(p) |c| {
+    fn mkdir(p: &Path, mode: c_int) -> bool {
+        do as_c_charp(p.to_str()) |c| {
             libc::mkdir(c, mode as mode_t) == (0 as c_int)
         }
     }
 }
 
 /// Lists the contents of a directory
-fn list_dir(+p: Path) -> ~[~str] {
+fn list_dir(p: &Path) -> ~[~str] {
 
     #[cfg(unix)]
-    fn star(+p: ~str) -> ~str { p }
+    fn star(p: &Path) -> Path { copy *p }
 
     #[cfg(windows)]
-    fn star(+p: ~str) -> ~str {
-        let pl = str::len(p);
-        if pl == 0u || (p[pl - 1u] as char != path::consts::path_sep
-                        || p[pl - 1u] as char != path::consts::alt_path_sep) {
-            p + path::path_sep() + ~"*"
-        } else {
-            p + ~"*"
-        }
-    }
+    fn star(p: &Path) -> Path { p.push("*") }
 
-    do rustrt::rust_list_files(star(p)).filter |filename| {
+    do rustrt::rust_list_files(star(p).to_str()).filter |filename| {
         filename != ~"." && filename != ~".."
     }
 }
@@ -627,90 +627,84 @@ fn list_dir(+p: Path) -> ~[~str] {
  *
  * This version prepends each entry with the directory.
  */
-fn list_dir_path(+p: Path) -> ~[~str] {
-    let mut p = p;
-    let pl = str::len(p);
-    if pl == 0u || (p[pl - 1u] as char != path::consts::path_sep
-                    && p[pl - 1u] as char != path::consts::alt_path_sep) {
-        p += path::path_sep();
-    }
-    os::list_dir(p).map(|f| p + f)
+fn list_dir_path(p: &Path) -> ~[~Path] {
+    os::list_dir(p).map(|f| ~p.push(f))
 }
 
 /// Removes a directory at the specified path
-fn remove_dir(+p: Path) -> bool {
+fn remove_dir(p: &Path) -> bool {
    return rmdir(p);
 
     #[cfg(windows)]
-    fn rmdir(+p: Path) -> bool {
+    fn rmdir(p: &Path) -> bool {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
-        return do as_utf16_p(p) |buf| {
+        return do as_utf16_p(p.to_str()) |buf| {
             RemoveDirectoryW(buf) != (0 as BOOL)
         };
     }
 
     #[cfg(unix)]
-    fn rmdir(+p: Path) -> bool {
-        return do as_c_charp(p) |buf| {
+    fn rmdir(p: &Path) -> bool {
+        return do as_c_charp(p.to_str()) |buf| {
             libc::rmdir(buf) == (0 as c_int)
         };
     }
 }
 
-fn change_dir(+p: Path) -> bool {
+fn change_dir(p: &Path) -> bool {
     return chdir(p);
 
     #[cfg(windows)]
-    fn chdir(+p: Path) -> bool {
+    fn chdir(p: &Path) -> bool {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
-        return do as_utf16_p(p) |buf| {
+        return do as_utf16_p(p.to_str()) |buf| {
             SetCurrentDirectoryW(buf) != (0 as BOOL)
         };
     }
 
     #[cfg(unix)]
-    fn chdir(+p: Path) -> bool {
-        return do as_c_charp(p) |buf| {
+    fn chdir(p: &Path) -> bool {
+        return do as_c_charp(p.to_str()) |buf| {
             libc::chdir(buf) == (0 as c_int)
         };
     }
 }
 
 /// Copies a file from one location to another
-fn copy_file(+from: Path, +to: Path) -> bool {
+fn copy_file(from: &Path, to: &Path) -> bool {
     return do_copy_file(from, to);
 
     #[cfg(windows)]
-    fn do_copy_file(+from: Path, +to: Path) -> bool {
+    fn do_copy_file(from: &Path, to: &Path) -> bool {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
-        return do as_utf16_p(from) |fromp| {
-            do as_utf16_p(to) |top| {
+        return do as_utf16_p(from.to_str()) |fromp| {
+            do as_utf16_p(to.to_str()) |top| {
                 CopyFileW(fromp, top, (0 as BOOL)) != (0 as BOOL)
             }
         }
     }
 
     #[cfg(unix)]
-    fn do_copy_file(+from: Path, +to: Path) -> bool {
-        let istream = do as_c_charp(from) |fromp| {
-            do as_c_charp(~"rb") |modebuf| {
+    fn do_copy_file(from: &Path, to: &Path) -> bool {
+        let istream = do as_c_charp(from.to_str()) |fromp| {
+            do as_c_charp("rb") |modebuf| {
                 libc::fopen(fromp, modebuf)
             }
         };
         if istream as uint == 0u {
             return false;
         }
-        let ostream = do as_c_charp(to) |top| {
-            do as_c_charp(~"w+b") |modebuf| {
+        let ostream = do as_c_charp(to.to_str()) |top| {
+            do as_c_charp("w+b") |modebuf| {
                 libc::fopen(top, modebuf)
             }
         };
@@ -746,24 +740,24 @@ fn copy_file(+from: Path, +to: Path) -> bool {
 }
 
 /// Deletes an existing file
-fn remove_file(+p: Path) -> bool {
+fn remove_file(p: &Path) -> bool {
     return unlink(p);
 
     #[cfg(windows)]
-    fn unlink(+p: Path) -> bool {
+    fn unlink(p: &Path) -> bool {
         // FIXME (similar to Issue #2006): remove imports when export globs
         // work properly.
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
-        return do as_utf16_p(p) |buf| {
+        return do as_utf16_p(p.to_str()) |buf| {
             DeleteFileW(buf) != (0 as BOOL)
         };
     }
 
     #[cfg(unix)]
-    fn unlink(+p: Path) -> bool {
-        return do as_c_charp(p) |buf| {
+    fn unlink(p: &Path) -> bool {
+        return do as_c_charp(p.to_str()) |buf| {
             libc::unlink(buf) == (0 as c_int)
         };
     }
@@ -887,11 +881,7 @@ mod tests {
         log(debug, path);
 
         // Hard to test this function
-        if os::sysname() != ~"win32" {
-            assert str::starts_with(path, path::path_sep());
-        } else {
-            assert path[1] == ':' as u8;
-        }
+        assert path.is_absolute;
     }
 
     #[test]
@@ -926,10 +916,10 @@ mod tests {
     fn test() {
         assert (!path::path_is_absolute(~"test-path"));
 
-        log(debug, ~"Current working directory: " + getcwd());
+        log(debug, ~"Current working directory: " + getcwd().to_str());
 
-        log(debug, make_absolute(~"test-path"));
-        log(debug, make_absolute(~"/usr/bin"));
+        log(debug, make_absolute(&Path("test-path")));
+        log(debug, make_absolute(&Path("/usr/bin")));
     }
 
     #[test]
@@ -938,7 +928,7 @@ mod tests {
         let oldhome = getenv(~"HOME");
 
         setenv(~"HOME", ~"/home/MountainView");
-        assert os::homedir() == some(~"/home/MountainView");
+        assert os::homedir() == some(Path("/home/MountainView"));
 
         setenv(~"HOME", ~"");
         assert os::homedir() == none;
@@ -959,16 +949,16 @@ mod tests {
         assert os::homedir() == none;
 
         setenv(~"HOME", ~"/home/MountainView");
-        assert os::homedir() == some(~"/home/MountainView");
+        assert os::homedir() == some(Path("/home/MountainView"));
 
         setenv(~"HOME", ~"");
 
         setenv(~"USERPROFILE", ~"/home/MountainView");
-        assert os::homedir() == some(~"/home/MountainView");
+        assert os::homedir() == some(Path("/home/MountainView"));
 
         setenv(~"HOME", ~"/home/MountainView");
         setenv(~"USERPROFILE", ~"/home/PaloAlto");
-        assert os::homedir() == some(~"/home/MountainView");
+        assert os::homedir() == some(Path("/home/MountainView"));
 
         option::iter(oldhome, |s| setenv(~"HOME", s));
         option::iter(olduserprofile,
@@ -977,16 +967,18 @@ mod tests {
 
     #[test]
     fn tmpdir() {
-        assert !str::is_empty(os::tmpdir());
+        assert !str::is_empty(os::tmpdir().to_str());
     }
 
     // Issue #712
     #[test]
-    fn test_list_dir_no_invalid_memory_access() { os::list_dir(~"."); }
+    fn test_list_dir_no_invalid_memory_access() {
+        os::list_dir(&Path("."));
+    }
 
     #[test]
     fn list_dir() {
-        let dirs = os::list_dir(~".");
+        let dirs = os::list_dir(&Path("."));
         // Just assuming that we've got some contents in the current directory
         assert (vec::len(dirs) > 0u);
 
@@ -995,34 +987,34 @@ mod tests {
 
     #[test]
     fn path_is_dir() {
-        assert (os::path_is_dir(~"."));
-        assert (!os::path_is_dir(~"test/stdtest/fs.rs"));
+        assert (os::path_is_dir(&Path(".")));
+        assert (!os::path_is_dir(&Path("test/stdtest/fs.rs")));
     }
 
     #[test]
     fn path_exists() {
-        assert (os::path_exists(~"."));
-        assert (!os::path_exists(~"test/nonexistent-bogus-path"));
+        assert (os::path_exists(&Path(".")));
+        assert (!os::path_exists(&Path("test/nonexistent-bogus-path")));
     }
 
     #[test]
     fn copy_file_does_not_exist() {
-      assert !os::copy_file(~"test/nonexistent-bogus-path",
-                           ~"test/other-bogus-path");
-      assert !os::path_exists(~"test/other-bogus-path");
+      assert !os::copy_file(&Path("test/nonexistent-bogus-path"),
+                            &Path("test/other-bogus-path"));
+      assert !os::path_exists(&Path("test/other-bogus-path"));
     }
 
     #[test]
     fn copy_file_ok() {
       let tempdir = getcwd(); // would like to use $TMPDIR,
                               // doesn't seem to work on Linux
-      assert (str::len(tempdir) > 0u);
-      let in = tempdir + path::path_sep() + ~"in.txt";
-      let out = tempdir + path::path_sep() + ~"out.txt";
+      assert (str::len(tempdir.to_str()) > 0u);
+      let in = tempdir.push("in.txt");
+      let out = tempdir.push("out.txt");
 
       /* Write the temp input file */
-        let ostream = do as_c_charp(in) |fromp| {
-            do as_c_charp(~"w+b") |modebuf| {
+        let ostream = do as_c_charp(in.to_str()) |fromp| {
+            do as_c_charp("w+b") |modebuf| {
                 libc::fopen(fromp, modebuf)
             }
       };
@@ -1034,14 +1026,14 @@ mod tests {
                                (str::len(s) + 1u) as size_t, ostream)
                   == buf.len() as size_t)};
       assert (libc::fclose(ostream) == (0u as c_int));
-      let rs = os::copy_file(in, out);
-      if (!os::path_exists(in)) {
-        fail (fmt!("%s doesn't exist", in));
+      let rs = os::copy_file(&in, &out);
+      if (!os::path_exists(&in)) {
+        fail (fmt!("%s doesn't exist", in.to_str()));
       }
       assert(rs);
-      let rslt = run::run_program(~"diff", ~[in, out]);
+      let rslt = run::run_program(~"diff", ~[in.to_str(), out.to_str()]);
       assert (rslt == 0);
-      assert (remove_file(in));
-      assert (remove_file(out));
+      assert (remove_file(&in));
+      assert (remove_file(&out));
     }
 }
diff --git a/src/libcore/path2.rs b/src/libcore/path2.rs
index 50996c7876b..9d1351db3ac 100644
--- a/src/libcore/path2.rs
+++ b/src/libcore/path2.rs
@@ -14,73 +14,82 @@ struct PosixPath {
     components: ~[~str];
 }
 
-trait Path {
+trait GenericPath {
 
-    static fn from_str((&str)) -> self;
-    fn to_str() -> ~str;
+    static pure fn from_str((&str)) -> self;
 
-    fn dirname() -> ~str;
-    fn filename() -> option<~str>;
-    fn filestem() -> option<~str>;
-    fn filetype() -> option<~str>;
+    pure fn dirname() -> ~str;
+    pure fn filename() -> option<~str>;
+    pure fn filestem() -> option<~str>;
+    pure fn filetype() -> option<~str>;
 
-    fn with_dirname((&str)) -> self;
-    fn with_filename((&str)) -> self;
-    fn with_filestem((&str)) -> self;
-    fn with_filetype((&str)) -> self;
+    pure fn with_dirname((&str)) -> self;
+    pure fn with_filename((&str)) -> self;
+    pure fn with_filestem((&str)) -> self;
+    pure fn with_filetype((&str)) -> self;
 
-    fn push_components((&[~str])) -> self;
-    fn pop_component() -> self;
+    pure fn push((&str)) -> self;
+    pure fn push_rel((&self)) -> self;
+    pure fn push_many((&[~str])) -> self;
+    pure fn pop() -> self;
 }
 
-// FIXME (#3227): when default methods in traits are working, de-duplicate
-// PosixPath and WindowsPath, most of their methods are common.
+#[cfg(windows)]
+type Path = WindowsPath;
+
+#[cfg(windows)]
+pure fn Path(s: &str) -> Path {
+    from_str::<WindowsPath>(s)
+}
+
+#[cfg(unix)]
+type Path = PosixPath;
 
-impl PosixPath : Path {
+#[cfg(unix)]
+pure fn Path(s: &str) -> Path {
+    from_str::<PosixPath>(s)
+}
+
+impl PosixPath : ToStr {
     fn to_str() -> ~str {
-        match self.filename() {
-          none => self.dirname(),
-          some(ref f) =>
-          if (self.components.len() == 1 &&
-              !self.is_absolute) {
-            copy *f
-          } else {
-            self.dirname() + "/" + *f
-          }
+        let mut s = ~"";
+        if self.is_absolute {
+            s += "/";
         }
+        s + str::connect(self.components, "/")
     }
+}
 
-    static fn from_str(s: &str) -> PosixPath {
+// FIXME (#3227): when default methods in traits are working, de-duplicate
+// PosixPath and WindowsPath, most of their methods are common.
+impl PosixPath : GenericPath {
+
+    static pure fn from_str(s: &str) -> PosixPath {
         let mut components = str::split_nonempty(s, |c| c == '/');
         let is_absolute = (s.len() != 0 && s[0] == '/' as u8);
         return PosixPath { is_absolute: is_absolute,
                            components: normalize(components) }
     }
 
-    fn dirname() -> ~str {
-        let mut s = ~"";
-        if self.is_absolute {
-            s += "/";
-        }
-        let mut d = copy self.components;
-        if d.len() != 0 {
-            vec::pop(d);
-        }
-        s += str::connect(d, "/");
-        if s.len() == 0 {
-            s = ~".";
+    pure fn dirname() -> ~str {
+        unchecked {
+            let s = self.dir_path().to_str();
+            if s.len() == 0 {
+                ~"."
+            } else {
+                s
+            }
         }
-        return s;
     }
 
-    fn filename() -> option<~str> {
+    pure fn filename() -> option<~str> {
         match self.components.len() {
           0 => none,
           n => some(copy self.components[n - 1])
         }
     }
 
-    fn filestem() -> option<~str> {
+    pure fn filestem() -> option<~str> {
         match self.filename() {
           none => none,
           some(ref f) => {
@@ -92,7 +101,7 @@ impl PosixPath : Path {
         }
     }
 
-    fn filetype() -> option<~str> {
+    pure fn filetype() -> option<~str> {
         match self.filename() {
           none => none,
           some(ref f) => {
@@ -104,20 +113,22 @@ impl PosixPath : Path {
         }
     }
 
-    fn with_dirname(d: &str) -> PosixPath {
+    pure fn with_dirname(d: &str) -> PosixPath {
         let dpath = from_str::<PosixPath>(d);
         match self.filename() {
-          some(ref f) => dpath.push_components(~[copy *f]),
+          some(ref f) => dpath.push(*f),
           none => dpath
         }
     }
 
-    fn with_filename(f: &str) -> PosixPath {
-        assert ! str::any(f, |c| windows::is_sep(c as u8));
-        self.dir_path().push_components(~[str::from_slice(f)])
+    pure fn with_filename(f: &str) -> PosixPath {
+        unchecked {
+            assert ! str::any(f, |c| windows::is_sep(c as u8));
+            self.dir_path().push(f)
+        }
     }
 
-    fn with_filestem(s: &str) -> PosixPath {
+    pure fn with_filestem(s: &str) -> PosixPath {
         match self.filetype() {
           none => self.with_filename(s),
           some(ref t) =>
@@ -125,7 +136,7 @@ impl PosixPath : Path {
         }
     }
 
-    fn with_filetype(t: &str) -> PosixPath {
+    pure fn with_filetype(t: &str) -> PosixPath {
         if t.len() == 0 {
             match self.filestem() {
               none => copy self,
@@ -141,15 +152,15 @@ impl PosixPath : Path {
         }
     }
 
-    fn dir_path() -> PosixPath {
+    pure fn dir_path() -> PosixPath {
         if self.components.len() != 0 {
-            self.pop_component()
+            self.pop()
         } else {
             copy self
         }
     }
 
-    fn file_path() -> PosixPath {
+    pure fn file_path() -> PosixPath {
         let cs = match self.filename() {
           none => ~[],
           some(ref f) => ~[copy *f]
@@ -158,42 +169,56 @@ impl PosixPath : Path {
                            components: cs }
     }
 
-    fn push_components(cs: &[~str]) -> PosixPath {
+    pure fn push_rel(other: &PosixPath) -> PosixPath {
+        assert !other.is_absolute;
+        self.push_many(other.components)
+    }
+
+    pure fn push_many(cs: &[~str]) -> PosixPath {
         return PosixPath { components: normalize(self.components + cs),
                            ..self }
     }
 
-    fn pop_component() -> PosixPath {
+    pure fn push(s: &str) -> PosixPath {
+        let mut cs = self.components;
+        unchecked { vec::push(cs, move str::from_slice(s)); }
+        cs = normalize(cs);
+        return PosixPath { components: move cs,
+                           ..self }
+    }
+
+    pure fn pop() -> PosixPath {
         let mut cs = copy self.components;
         if cs.len() != 0 {
-            vec::pop(cs);
+            unchecked { vec::pop(cs); }
         }
-        return PosixPath { components: cs, ..self }
+        return PosixPath { components: move cs, ..self }
     }
-
-
-
 }
 
 
-impl WindowsPath : Path {
-
+impl WindowsPath : ToStr {
     fn to_str() -> ~str {
-        match self.filename() {
-          none => self.dirname(),
-          some(ref f) =>
-          if (self.components.len() == 1 &&
-              !self.is_absolute &&
-              self.host == none &&
-              self.device == none) {
-            copy *f
-          } else {
-            self.dirname() + "\\" + *f
-          }
+        let mut s = ~"";
+        match self.host {
+          some(h) => { s += "\\\\"; s += h; }
+          none => { }
+        }
+        match self.device {
+          some(d) => { s += d; s += ":"; }
+          none => { }
+        }
+        if self.is_absolute {
+            s += "\\";
         }
+        s + str::connect(self.components, "\\")
     }
+}
+
 
-    static fn from_str(s: &str) -> WindowsPath {
+impl WindowsPath : GenericPath {
+
+    static pure fn from_str(s: &str) -> WindowsPath {
         let host;
         let device;
         let rest;
@@ -229,38 +254,25 @@ impl WindowsPath : Path {
                              components: normalize(components) }
     }
 
-    fn dirname() -> ~str {
-        let mut s = ~"";
-        match self.host {
-          some(h) => { s += "\\\\"; s += h; }
-          none => { }
-        }
-        match self.device {
-          some(d) => { s += d; s += ":"; }
-          none => { }
-        }
-        if self.is_absolute {
-            s += "\\";
-        }
-        let mut d = copy self.components;
-        if d.len() != 0 {
-            vec::pop(d);
-        }
-        s += str::connect(d, "\\");
-        if s.len() == 0 {
-            s = ~".";
+    pure fn dirname() -> ~str {
+        unchecked {
+            let s = self.dir_path().to_str();
+            if s.len() == 0 {
+                ~"."
+            } else {
+                s
+            }
         }
-        return s;
     }
 
-    fn filename() -> option<~str> {
+    pure fn filename() -> option<~str> {
         match self.components.len() {
           0 => none,
           n => some(copy self.components[n - 1])
         }
     }
 
-    fn filestem() -> option<~str> {
+    pure fn filestem() -> option<~str> {
         match self.filename() {
           none => none,
           some(ref f) => {
@@ -272,7 +284,7 @@ impl WindowsPath : Path {
         }
     }
 
-    fn filetype() -> option<~str> {
+    pure fn filetype() -> option<~str> {
         match self.filename() {
           none => none,
           some(ref f) => {
@@ -284,20 +296,20 @@ impl WindowsPath : Path {
         }
     }
 
-    fn with_dirname(d: &str) -> WindowsPath {
+    pure fn with_dirname(d: &str) -> WindowsPath {
         let dpath = from_str::<WindowsPath>(d);
         match self.filename() {
-          some(ref f) => dpath.push_components(~[copy *f]),
+          some(ref f) => dpath.push(*f),
           none => dpath
         }
     }
 
-    fn with_filename(f: &str) -> WindowsPath {
+    pure fn with_filename(f: &str) -> WindowsPath {
         assert ! str::any(f, |c| windows::is_sep(c as u8));
-        self.dir_path().push_components(~[str::from_slice(f)])
+        self.dir_path().push(f)
     }
 
-    fn with_filestem(s: &str) -> WindowsPath {
+    pure fn with_filestem(s: &str) -> WindowsPath {
         match self.filetype() {
           none => self.with_filename(s),
           some(ref t) =>
@@ -305,7 +317,7 @@ impl WindowsPath : Path {
         }
     }
 
-    fn with_filetype(t: &str) -> WindowsPath {
+    pure fn with_filetype(t: &str) -> WindowsPath {
         if t.len() == 0 {
             match self.filestem() {
               none => copy self,
@@ -321,15 +333,15 @@ impl WindowsPath : Path {
         }
     }
 
-    fn dir_path() -> WindowsPath {
+    pure fn dir_path() -> WindowsPath {
         if self.components.len() != 0 {
-            self.pop_component()
+            self.pop()
         } else {
             copy self
         }
     }
 
-    fn file_path() -> WindowsPath {
+    pure fn file_path() -> WindowsPath {
         let cs = match self.filename() {
           none => ~[],
           some(ref f) => ~[copy *f]
@@ -340,30 +352,47 @@ impl WindowsPath : Path {
                              components: cs }
     }
 
-    fn push_components(cs: &[~str]) -> WindowsPath {
+    pure fn push_rel(other: &WindowsPath) -> WindowsPath {
+        assert !other.is_absolute;
+        self.push_many(other.components)
+    }
+
+    pure fn push_many(cs: &[~str]) -> WindowsPath {
         return WindowsPath { components: normalize(self.components + cs),
                             ..self }
     }
 
-    fn pop_component() -> WindowsPath {
+    pure fn push(s: &str) -> WindowsPath {
+        let mut cs = self.components;
+        unchecked { vec::push(cs, move str::from_slice(s)); }
+        cs = normalize(cs);
+        return WindowsPath { components: move cs,
+                             ..self }
+    }
+
+    pure fn pop() -> WindowsPath {
         let mut cs = copy self.components;
         if cs.len() != 0 {
-            vec::pop(cs);
+            unchecked { vec::pop(cs); }
         }
-        return WindowsPath { components: cs, ..self }
+        return WindowsPath { components: move cs, ..self }
     }
 }
 
 
-fn normalize(components: &[~str]) -> ~[~str] {
+pure fn normalize(components: &[~str]) -> ~[~str] {
     let mut cs = ~[];
-    for components.each |c| {
-        if c == ~"." { again; }
-        if c == ~".." && cs.len() != 0 {
-            vec::pop(cs);
-            again;
+    unchecked {
+        for components.each |c| {
+            unchecked {
+                if c == ~"." && components.len() > 1 { again; }
+                if c == ~".." && cs.len() != 0 {
+                    vec::pop(cs);
+                    again;
+                }
+                vec::push(cs, copy c);
+            }
         }
-        vec::push(cs, copy c);
     }
     cs
 }
@@ -384,6 +413,7 @@ mod posix {
         }
 
         t(&(mk("hi")), "hi");
+        t(&(mk("/lib")), "/lib");
         t(&(mk("hi/there")), "hi/there");
         t(&(mk("hi/there.txt")), "hi/there.txt");
 
@@ -401,7 +431,7 @@ mod posix {
           "a/foo.txt");
 
         t(&(mk("a/b/c")
-            .push_components([~".."])), "a/b");
+            .push("..")), "a/b");
 
         t(&(mk("there.txt")
             .with_filetype("o")), "there.o");
@@ -425,7 +455,7 @@ mod posix {
             "/usr/lib/there.o");
 
         t(&(mk("/usr/bin/rust")
-            .push_components([~"lib", ~"thingy.so"])
+            .push_many([~"lib", ~"thingy.so"])
             .with_filestem("librustc")),
           "/usr/bin/rust/lib/librustc.so");
 
@@ -437,11 +467,11 @@ mod posix {
 mod windows {
 
     #[inline(always)]
-    fn is_sep(u: u8) -> bool {
+    pure fn is_sep(u: u8) -> bool {
         u == '/' as u8 || u == '\\' as u8
     }
 
-    fn extract_unc_prefix(s: &str) -> option<(~str,~str)> {
+    pure fn extract_unc_prefix(s: &str) -> option<(~str,~str)> {
         if (s.len() > 1 &&
             s[0] == '\\' as u8 &&
             s[1] == '\\' as u8) {
@@ -458,14 +488,20 @@ mod windows {
         none
     }
 
-    fn extract_drive_prefix(s: &str) -> option<(~str,~str)> {
-        if (s.len() > 1 &&
-            libc::isalpha(s[0] as libc::c_int) != 0 &&
-            s[1] == ':' as u8) {
-            let rest = if s.len() == 2 { ~"" } else { s.slice(2, s.len()) };
-            return some((s.slice(0,1), rest));
+    pure fn extract_drive_prefix(s: &str) -> option<(~str,~str)> {
+        unchecked {
+            if (s.len() > 1 &&
+                libc::isalpha(s[0] as libc::c_int) != 0 &&
+                s[1] == ':' as u8) {
+                let rest = if s.len() == 2 {
+                    ~""
+                } else {
+                    s.slice(2, s.len())
+                };
+                return some((s.slice(0,1), rest));
+            }
+            none
         }
-        none
     }
 
     #[test]
@@ -532,7 +568,7 @@ mod windows {
             "c:\\program files C\\there.o");
 
         t(&(mk("c:\\program files (x86)\\rust")
-            .push_components([~"lib", ~"thingy.dll"])
+            .push_many([~"lib", ~"thingy.dll"])
             .with_filename("librustc.dll")),
           "c:\\program files (x86)\\rust\\lib\\librustc.dll");
 
diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs
index a4e68c78bba..8aa798d4576 100644
--- a/src/libstd/tempfile.rs
+++ b/src/libstd/tempfile.rs
@@ -4,13 +4,14 @@ import core::option;
 import option::{none, some};
 import rand;
 
-fn mkdtemp(prefix: ~str, suffix: ~str) -> option<~str> {
+fn mkdtemp(tmpdir: &Path, suffix: &str) -> option<Path> {
     let r = rand::rng();
     let mut i = 0u;
     while (i < 1000u) {
-        let s = prefix + r.gen_str(16u) + suffix;
-        if os::make_dir(s, 0x1c0i32) {  // FIXME: u+rwx (#2349)
-            return some(s);
+        let p = tmpdir.push(r.gen_str(16u) +
+                            str::from_slice(suffix));
+        if os::make_dir(&p, 0x1c0i32) {  // FIXME: u+rwx (#2349)
+            return some(p);
         }
         i += 1u;
     }
@@ -19,11 +20,11 @@ fn mkdtemp(prefix: ~str, suffix: ~str) -> option<~str> {
 
 #[test]
 fn test_mkdtemp() {
-    let r = mkdtemp(~"./", ~"foobar");
+    let r = mkdtemp(&Path("."), "foobar");
     match r {
         some(p) => {
-            os::remove_dir(p);
-            assert(str::ends_with(p, ~"foobar"));
+            os::remove_dir(&p);
+            assert(str::ends_with(p.to_str(), "foobar"));
         }
         _ => assert(false)
     }
diff --git a/src/libstd/test.rs b/src/libstd/test.rs
index a0cc26b6658..bd22b8b56d2 100644
--- a/src/libstd/test.rs
+++ b/src/libstd/test.rs
@@ -141,7 +141,7 @@ fn run_tests_console(opts: test_opts,
     }
 
     let log_out = match opts.logfile {
-        some(path) => match io::file_writer(path,
+        some(path) => match io::file_writer(&Path(path),
                                             ~[io::Create, io::Truncate]) {
           result::ok(w) => some(w),
           result::err(s) => {
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index b74a1165b79..881691b5f5c 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -59,7 +59,7 @@ fn expand_include(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
     let args = get_mac_args(cx, sp, arg, 1u, option::some(1u), ~"include");
     let file = expr_to_str(cx, args[0], ~"#include_str requires a string");
     let p = parse::new_parser_from_file(cx.parse_sess(), cx.cfg(),
-                                        res_rel_file(cx, sp, file),
+                                        &res_rel_file(cx, sp, &Path(file)),
                                         parse::parser::SOURCE_FILE);
     return p.parse_expr();
 }
@@ -70,7 +70,7 @@ fn expand_include_str(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
 
     let file = expr_to_str(cx, args[0], ~"#include_str requires a string");
 
-    let res = io::read_whole_file_str(res_rel_file(cx, sp, file));
+    let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path(file)));
     match res {
       result::ok(_) => { /* Continue. */ }
       result::err(e) => {
@@ -87,7 +87,7 @@ fn expand_include_bin(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
 
     let file = expr_to_str(cx, args[0], ~"#include_bin requires a string");
 
-    match io::read_whole_file(res_rel_file(cx, sp, file)) {
+    match io::read_whole_file(&res_rel_file(cx, sp, &Path(file))) {
       result::ok(src) => {
         let u8_exprs = vec::map(src, |char: u8| {
             mk_u8(cx, sp, char)
@@ -100,14 +100,13 @@ fn expand_include_bin(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
     }
 }
 
-fn res_rel_file(cx: ext_ctxt, sp: codemap::span, +arg: Path) -> Path {
+fn res_rel_file(cx: ext_ctxt, sp: codemap::span, arg: &Path) -> Path {
     // NB: relative paths are resolved relative to the compilation unit
-    if !path::path_is_absolute(arg) {
-        let cu = codemap::span_to_filename(sp, cx.codemap());
-        let dir = path::dirname(cu);
-        return path::connect(dir, arg);
+    if !arg.is_absolute {
+        let cu = Path(codemap::span_to_filename(sp, cx.codemap()));
+        cu.dir_path().push_many(arg.components)
     } else {
-        return arg;
+        copy *arg
     }
 }
 
diff --git a/src/libsyntax/parse.rs b/src/libsyntax/parse.rs
index bb21ba92679..b83c687b94b 100644
--- a/src/libsyntax/parse.rs
+++ b/src/libsyntax/parse.rs
@@ -49,33 +49,33 @@ fn new_parse_sess_special_handler(sh: span_handler, cm: codemap::codemap)
              mut chpos: 0u, mut byte_pos: 0u};
 }
 
-fn parse_crate_from_file(input: ~str, cfg: ast::crate_cfg,
+fn parse_crate_from_file(input: &Path, cfg: ast::crate_cfg,
                          sess: parse_sess) -> @ast::crate {
-    if str::ends_with(input, ~".rc") {
+    if input.filetype() == some(~"rc") {
         parse_crate_from_crate_file(input, cfg, sess)
-    } else if str::ends_with(input, ~".rs") {
+    } else if input.filetype() == some(~"rs") {
         parse_crate_from_source_file(input, cfg, sess)
     } else {
         sess.span_diagnostic.handler().fatal(~"unknown input file type: " +
-                                             input)
+                                             input.to_str())
     }
 }
 
-fn parse_crate_from_crate_file(input: ~str, cfg: ast::crate_cfg,
+fn parse_crate_from_crate_file(input: &Path, cfg: ast::crate_cfg,
                                sess: parse_sess) -> @ast::crate {
     let (p, rdr) = new_parser_etc_from_file(sess, cfg, input,
                                             parser::CRATE_FILE);
     let lo = p.span.lo;
-    let prefix = path::dirname(input);
+    let prefix = input.dir_path();
     let leading_attrs = p.parse_inner_attrs_and_next();
     let { inner: crate_attrs, next: first_cdir_attr } = leading_attrs;
     let cdirs = p.parse_crate_directives(token::EOF, first_cdir_attr);
     sess.chpos = rdr.chpos;
     sess.byte_pos = sess.byte_pos + rdr.pos;
     let cx = @{sess: sess, cfg: /* FIXME (#2543) */ copy p.cfg};
-    let (companionmod, _) = path::splitext(path::basename(input));
+    let companionmod = option::map(input.filestem(), |s| Path(s));
     let (m, attrs) = eval::eval_crate_directives_to_mod(
-        cx, cdirs, prefix, option::some(companionmod));
+        cx, cdirs, &prefix, &companionmod);
     let mut hi = p.span.hi;
     p.expect(token::EOF);
     return @ast_util::respan(ast_util::mk_sp(lo, hi),
@@ -85,7 +85,7 @@ fn parse_crate_from_crate_file(input: ~str, cfg: ast::crate_cfg,
                            config: /* FIXME (#2543) */ copy p.cfg});
 }
 
-fn parse_crate_from_source_file(input: ~str, cfg: ast::crate_cfg,
+fn parse_crate_from_source_file(input: &Path, cfg: ast::crate_cfg,
                                 sess: parse_sess) -> @ast::crate {
     let (p, rdr) = new_parser_etc_from_file(sess, cfg, input,
                                             parser::SOURCE_FILE);
@@ -183,7 +183,7 @@ fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
 
 
 fn new_parser_etc_from_file(sess: parse_sess, cfg: ast::crate_cfg,
-                            +path: ~str, ftype: parser::file_type) ->
+                            path: &Path, ftype: parser::file_type) ->
    (parser, string_reader) {
     let res = io::read_whole_file_str(path);
     match res {
@@ -191,14 +191,15 @@ fn new_parser_etc_from_file(sess: parse_sess, cfg: ast::crate_cfg,
       result::err(e) => sess.span_diagnostic.handler().fatal(e)
     }
     let src = @result::unwrap(res);
-    let filemap = codemap::new_filemap(path, src, sess.chpos, sess.byte_pos);
+    let filemap = codemap::new_filemap(path.to_str(), src,
+                                       sess.chpos, sess.byte_pos);
     sess.cm.files.push(filemap);
     let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap,
                                         sess.interner);
     return (parser(sess, cfg, srdr as reader, ftype), srdr);
 }
 
-fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, +path: ~str,
+fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, path: &Path,
                         ftype: parser::file_type) -> parser {
     let (p, _) = new_parser_etc_from_file(sess, cfg, path, ftype);
     return p;
diff --git a/src/libsyntax/parse/eval.rs b/src/libsyntax/parse/eval.rs
index 615d546bb96..54ec79de4c1 100644
--- a/src/libsyntax/parse/eval.rs
+++ b/src/libsyntax/parse/eval.rs
@@ -9,7 +9,7 @@ type ctx =
 
 fn eval_crate_directives(cx: ctx,
                          cdirs: ~[@ast::crate_directive],
-                         prefix: ~str,
+                         prefix: &Path,
                          &view_items: ~[@ast::view_item],
                          &items: ~[@ast::item]) {
     for cdirs.each |sub_cdir| {
@@ -18,11 +18,8 @@ fn eval_crate_directives(cx: ctx,
 }
 
 fn eval_crate_directives_to_mod(cx: ctx, cdirs: ~[@ast::crate_directive],
-                                prefix: ~str, suffix: option<~str>)
+                                prefix: &Path, suffix: &option<Path>)
     -> (ast::_mod, ~[ast::attribute]) {
-    debug!("eval crate prefix: %s", prefix);
-    debug!("eval crate suffix: %s",
-           option::get_default(suffix, ~"none"));
     let (cview_items, citems, cattrs)
         = parse_companion_mod(cx, prefix, suffix);
     let mut view_items: ~[@ast::view_item] = ~[];
@@ -43,17 +40,17 @@ companion mod is a .rs file with the same name as the directory.
 We build the path to the companion mod by combining the prefix and the
 optional suffix then adding the .rs extension.
 */
-fn parse_companion_mod(cx: ctx, prefix: ~str, suffix: option<~str>)
+fn parse_companion_mod(cx: ctx, prefix: &Path, suffix: &option<Path>)
     -> (~[@ast::view_item], ~[@ast::item], ~[ast::attribute]) {
 
-    fn companion_file(+prefix: ~str, suffix: option<~str>) -> ~str {
-        return match suffix {
-          option::some(s) => path::connect(prefix, s),
-          option::none => prefix
-        } + ~".rs";
+    fn companion_file(prefix: &Path, suffix: &option<Path>) -> Path {
+        return match *suffix {
+          option::some(s) => prefix.push_many(s.components),
+          option::none => copy *prefix
+        }.with_filetype("rs");
     }
 
-    fn file_exists(path: ~str) -> bool {
+    fn file_exists(path: &Path) -> bool {
         // Crude, but there's no lib function for this and I'm not
         // up to writing it just now
         match io::file_reader(path) {
@@ -62,8 +59,7 @@ fn parse_companion_mod(cx: ctx, prefix: ~str, suffix: option<~str>)
         }
     }
 
-    let modpath = companion_file(prefix, suffix);
-    debug!("looking for companion mod %s", modpath);
+    let modpath = &companion_file(prefix, suffix);
     if file_exists(modpath) {
         debug!("found companion mod");
         let (p0, r0) = new_parser_etc_from_file(cx.sess, cx.cfg,
@@ -85,19 +81,21 @@ fn cdir_path_opt(default: ~str, attrs: ~[ast::attribute]) -> ~str {
     }
 }
 
-fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: ~str,
+fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: &Path,
                         &view_items: ~[@ast::view_item],
                         &items: ~[@ast::item]) {
     match cdir.node {
       ast::cdir_src_mod(id, attrs) => {
-        let file_path = cdir_path_opt((cx.sess.interner.get(id) + ~".rs"),
-                                      attrs);
-        let full_path =
-            if path::path_is_absolute(file_path) {
-                file_path
-            } else { prefix + path::path_sep() + file_path };
+        let file_path = Path(cdir_path_opt(
+            cx.sess.interner.get(id) + ~".rs", attrs));
+        let full_path = if file_path.is_absolute {
+            copy file_path
+        } else {
+            prefix.push_many(file_path.components)
+        };
         let (p0, r0) =
-            new_parser_etc_from_file(cx.sess, cx.cfg, full_path, SOURCE_FILE);
+            new_parser_etc_from_file(cx.sess, cx.cfg,
+                                     &full_path, SOURCE_FILE);
         let inner_attrs = p0.parse_inner_attrs_and_next();
         let mod_attrs = vec::append(attrs, inner_attrs.inner);
         let first_item_outer_attrs = inner_attrs.next;
@@ -112,13 +110,14 @@ fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: ~str,
         vec::push(items, i);
       }
       ast::cdir_dir_mod(id, cdirs, attrs) => {
-        let path = cdir_path_opt(*cx.sess.interner.get(id), attrs);
-        let full_path =
-            if path::path_is_absolute(path) {
-                path
-            } else { prefix + path::path_sep() + path };
+        let path = Path(cdir_path_opt(*cx.sess.interner.get(id), attrs));
+        let full_path = if path.is_absolute {
+            copy path
+        } else {
+            prefix.push_many(path.components)
+        };
         let (m0, a0) = eval_crate_directives_to_mod(
-            cx, cdirs, full_path, none);
+            cx, cdirs, &full_path, &none);
         let i =
             @{ident: /* FIXME (#2543) */ copy id,
               attrs: vec::append(attrs, a0),
diff --git a/src/rustc/back/link.rs b/src/rustc/back/link.rs
index 33fce8bc72c..7c227e012a9 100644
--- a/src/rustc/back/link.rs
+++ b/src/rustc/back/link.rs
@@ -57,18 +57,7 @@ mod write {
         return false;
     }
 
-    // Decides what to call an intermediate file, given the name of the output
-    // and the extension to use.
-    fn mk_intermediate_name(output_path: ~str, extension: ~str) ->
-        ~str unsafe {
-        let stem = match str::find_char(output_path, '.') {
-          some(dot_pos) => str::slice(output_path, 0u, dot_pos),
-          none => output_path
-        };
-        return stem + ~"." + extension;
-    }
-
-    fn run_passes(sess: session, llmod: ModuleRef, output: ~str) {
+    fn run_passes(sess: session, llmod: ModuleRef, output: &Path) {
         let opts = sess.opts;
         if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
         let mut pm = mk_pass_manager();
@@ -85,15 +74,15 @@ mod write {
             match opts.output_type {
               output_type_bitcode => {
                 if opts.optimize != session::No {
-                    let filename = mk_intermediate_name(output, ~"no-opt.bc");
-                    str::as_c_str(filename, |buf| {
+                    let filename = output.with_filetype("no-opt.bc");
+                    str::as_c_str(filename.to_str(), |buf| {
                         llvm::LLVMWriteBitcodeToFile(llmod, buf)
                     });
                 }
               }
               _ => {
-                let filename = mk_intermediate_name(output, ~"bc");
-                str::as_c_str(filename, |buf| {
+                let filename = output.with_filetype("bc");
+                str::as_c_str(filename.to_str(), |buf| {
                     llvm::LLVMWriteBitcodeToFile(llmod, buf)
                 });
               }
@@ -163,9 +152,9 @@ mod write {
             if opts.save_temps {
                 // Always output the bitcode file with --save-temps
 
-                let filename = mk_intermediate_name(output, ~"opt.bc");
+                let filename = output.with_filetype("opt.bc");
                 llvm::LLVMRunPassManager(pm.llpm, llmod);
-                str::as_c_str(filename, |buf| {
+                str::as_c_str(filename.to_str(), |buf| {
                     llvm::LLVMWriteBitcodeToFile(llmod, buf)
                 });
                 pm = mk_pass_manager();
@@ -175,7 +164,7 @@ mod write {
                     let _: () = str::as_c_str(
                         sess.targ_cfg.target_strs.target_triple,
                         |buf_t| {
-                            str::as_c_str(output, |buf_o| {
+                            str::as_c_str(output.to_str(), |buf_o| {
                                 WriteOutputFile(
                                     sess,
                                     pm.llpm,
@@ -197,7 +186,7 @@ mod write {
                     let _: () = str::as_c_str(
                         sess.targ_cfg.target_strs.target_triple,
                         |buf_t| {
-                            str::as_c_str(output, |buf_o| {
+                            str::as_c_str(output.to_str(), |buf_o| {
                                 WriteOutputFile(
                                     sess,
                                     pm.llpm,
@@ -217,7 +206,7 @@ mod write {
                 let _: () = str::as_c_str(
                     sess.targ_cfg.target_strs.target_triple,
                     |buf_t| {
-                        str::as_c_str(output, |buf_o| {
+                        str::as_c_str(output.to_str(), |buf_o| {
                             WriteOutputFile(
                                 sess,
                                 pm.llpm,
@@ -239,13 +228,13 @@ mod write {
 
         if opts.output_type == output_type_llvm_assembly {
             // Given options "-S --emit-llvm": output LLVM assembly
-            str::as_c_str(output, |buf_o| {
+            str::as_c_str(output.to_str(), |buf_o| {
                 llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o)});
         } else {
             // If only a bitcode file is asked for by using the '--emit-llvm'
             // flag, then output it here
             llvm::LLVMRunPassManager(pm.llpm, llmod);
-            str::as_c_str(output,
+            str::as_c_str(output.to_str(),
                         |buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) );
         }
 
@@ -306,7 +295,7 @@ mod write {
  *
  */
 
-fn build_link_meta(sess: session, c: ast::crate, output: ~str,
+fn build_link_meta(sess: session, c: ast::crate, output: &Path,
                    symbol_hasher: &hash::State) -> link_meta {
 
     type provided_metas =
@@ -384,21 +373,16 @@ fn build_link_meta(sess: session, c: ast::crate, output: ~str,
     }
 
     fn crate_meta_name(sess: session, _crate: ast::crate,
-                       output: ~str, metas: provided_metas) -> ~str {
+                       output: &Path, metas: provided_metas) -> ~str {
         return match metas.name {
               some(v) => v,
               none => {
-                let name =
-                    {
-                        let mut os =
-                            str::split_char(path::basename(output), '.');
-                        if (vec::len(os) < 2u) {
-                            sess.fatal(fmt!("output file name `%s` doesn't\
-                              appear to have an extension", output));
-                        }
-                        vec::pop(os);
-                        str::connect(os, ~".")
-                    };
+                let name = match output.filestem() {
+                  none => sess.fatal(fmt!("output file name `%s` doesn't\
+                                           appear to have a stem",
+                                          output.to_str())),
+                  some(s) => s
+                };
                 warn_missing(sess, ~"name", name);
                 name
               }
@@ -552,31 +536,17 @@ fn mangle_internal_name_by_seq(ccx: @crate_ctxt, flav: ~str) -> ~str {
 // If the user wants an exe generated we need to invoke
 // cc to link the object file with some libs
 fn link_binary(sess: session,
-               obj_filename: ~str,
-               out_filename: ~str,
+               obj_filename: &Path,
+               out_filename: &Path,
                lm: link_meta) {
-    // Converts a library file name into a cc -l argument
-    fn unlib(config: @session::config, filename: ~str) -> ~str unsafe {
-        let rmlib = fn@(filename: ~str) -> ~str {
-            let found = str::find_str(filename, ~"lib");
-            if config.os == session::os_macos ||
-                (config.os == session::os_linux ||
-                 config.os == session::os_freebsd) &&
-                option::is_some(found) && option::get(found) == 0u {
-                return str::slice(filename, 3u, str::len(filename));
-            } else { return filename; }
-        };
-        fn rmext(filename: ~str) -> ~str {
-            let mut parts = str::split_char(filename, '.');
-            vec::pop(parts);
-            return str::connect(parts, ~".");
+    // Converts a library file-stem into a cc -l argument
+    fn unlib(config: @session::config, stem: ~str) -> ~str {
+        if stem.starts_with("lib") &&
+            config.os != session::os_win32 {
+            stem.slice(3, stem.len())
+        } else {
+            stem
         }
-        return match config.os {
-              session::os_macos => rmext(rmlib(filename)),
-              session::os_linux => rmext(rmlib(filename)),
-              session::os_freebsd => rmext(rmlib(filename)),
-              _ => rmext(filename)
-            };
     }
 
     let output = if sess.building_library {
@@ -585,17 +555,19 @@ fn link_binary(sess: session,
                                   lm.name, lm.extras_hash, lm.vers));
         debug!("link_meta.name:  %s", lm.name);
         debug!("long_libname: %s", long_libname);
-        debug!("out_filename: %s", out_filename);
-        debug!("dirname(out_filename): %s", path::dirname(out_filename));
+        debug!("out_filename: %s", out_filename.to_str());
+        debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
 
-        path::connect(path::dirname(out_filename), long_libname)
-    } else { out_filename };
+        out_filename.dir_path().push(long_libname)
+    } else {
+        *out_filename
+    };
 
-    log(debug, ~"output: " + output);
+    log(debug, ~"output: " + output.to_str());
 
     // The default library location, we need this to find the runtime.
     // The location of crates will be determined as needed.
-    let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path();
+    let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str();
 
     // In the future, FreeBSD will use clang as default compiler.
     // It would be flexible to use cc (system's default C compiler)
@@ -609,27 +581,28 @@ fn link_binary(sess: session,
     let mut cc_args =
         vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
     vec::push(cc_args, ~"-o");
-    vec::push(cc_args, output);
-    vec::push(cc_args, obj_filename);
+    vec::push(cc_args, output.to_str());
+    vec::push(cc_args, obj_filename.to_str());
 
     let mut lib_cmd;
     let os = sess.targ_cfg.os;
     if os == session::os_macos {
         lib_cmd = ~"-dynamiclib";
-    } else { lib_cmd = ~"-shared"; }
+    } else {
+        lib_cmd = ~"-shared";
+    }
 
     // # Crate linking
 
     let cstore = sess.cstore;
     for cstore::get_used_crate_files(cstore).each |cratepath| {
-        if str::ends_with(cratepath, ~".rlib") {
-            vec::push(cc_args, cratepath);
+        if cratepath.filetype() == some(~"rlib") {
+            vec::push(cc_args, cratepath.to_str());
             again;
         }
-        let cratepath = cratepath;
-        let dir = path::dirname(cratepath);
+        let dir = cratepath.dirname();
         if dir != ~"" { vec::push(cc_args, ~"-L" + dir); }
-        let libarg = unlib(sess.targ_cfg, path::basename(cratepath));
+        let libarg = unlib(sess.targ_cfg, option::get(cratepath.filestem()));
         vec::push(cc_args, ~"-l" + libarg);
     }
 
@@ -645,7 +618,7 @@ fn link_binary(sess: session,
     // forces to make sure that library can be found at runtime.
 
     let addl_paths = sess.opts.addl_lib_search_paths;
-    for addl_paths.each |path| { vec::push(cc_args, ~"-L" + path); }
+    for addl_paths.each |path| { vec::push(cc_args, ~"-L" + path.to_str()); }
 
     // The names of the extern libraries
     let used_libs = cstore::get_used_libraries(cstore);
@@ -658,7 +631,7 @@ fn link_binary(sess: session,
         // be rpathed
         if sess.targ_cfg.os == session::os_macos {
             vec::push(cc_args, ~"-Wl,-install_name,@rpath/"
-                      + path::basename(output));
+                      + option::get(output.filename()));
         }
     }
 
@@ -701,7 +674,7 @@ fn link_binary(sess: session,
 
     // FIXME (#2397): At some point we want to rpath our guesses as to where
     // extern libraries might live, based on the addl_lib_search_paths
-    vec::push_all(cc_args, rpath::get_rpath_flags(sess, output));
+    vec::push_all(cc_args, rpath::get_rpath_flags(sess, &output));
 
     debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" "));
     // We run 'cc' here
@@ -717,14 +690,14 @@ fn link_binary(sess: session,
 
     // Clean up on Darwin
     if sess.targ_cfg.os == session::os_macos {
-        run::run_program(~"dsymutil", ~[output]);
+        run::run_program(~"dsymutil", ~[output.to_str()]);
     }
 
     // Remove the temporary object file if we aren't saving temps
     if !sess.opts.save_temps {
         if ! os::remove_file(obj_filename) {
             sess.warn(fmt!("failed to delete object file `%s`",
-                           obj_filename));
+                           obj_filename.to_str()));
         }
     }
 }
diff --git a/src/rustc/back/rpath.rs b/src/rustc/back/rpath.rs
index b6f6d17e444..0d02821a24c 100644
--- a/src/rustc/back/rpath.rs
+++ b/src/rustc/back/rpath.rs
@@ -13,7 +13,7 @@ pure fn not_win32(os: session::os) -> bool {
   }
 }
 
-fn get_rpath_flags(sess: session::session, out_filename: ~str) -> ~[~str] {
+fn get_rpath_flags(sess: session::session, out_filename: &Path) -> ~[~str] {
     let os = sess.targ_cfg.os;
 
     // No rpath on windows
@@ -23,7 +23,6 @@ fn get_rpath_flags(sess: session::session, out_filename: ~str) -> ~[~str] {
 
     debug!("preparing the RPATH!");
 
-    let cwd = os::getcwd();
     let sysroot = sess.filesearch.sysroot();
     let output = out_filename;
     let libs = cstore::get_used_crate_files(sess.cstore);
@@ -32,50 +31,48 @@ fn get_rpath_flags(sess: session::session, out_filename: ~str) -> ~[~str] {
     let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess));
 
     let target_triple = sess.opts.target_triple;
-    let rpaths = get_rpaths(os, cwd, sysroot, output, libs, target_triple);
+    let rpaths = get_rpaths(os, &sysroot, output, libs, target_triple);
     rpaths_to_flags(rpaths)
 }
 
-fn get_sysroot_absolute_rt_lib(sess: session::session) -> path::Path {
-    let mut path = vec::append(~[sess.filesearch.sysroot()],
-                           filesearch::relative_target_lib_path(
-                               sess.opts.target_triple));
-    vec::push(path, os::dll_filename(~"rustrt"));
-    path::connect_many(path)
+fn get_sysroot_absolute_rt_lib(sess: session::session) -> Path {
+    let r = filesearch::relative_target_lib_path(sess.opts.target_triple);
+    sess.filesearch.sysroot().push_rel(&r).push(os::dll_filename("rustrt"))
 }
 
-fn rpaths_to_flags(rpaths: ~[~str]) -> ~[~str] {
-    vec::map(rpaths, |rpath| fmt!("-Wl,-rpath,%s",rpath) )
+fn rpaths_to_flags(rpaths: &[Path]) -> ~[~str] {
+    vec::map(rpaths, |rpath| fmt!("-Wl,-rpath,%s",rpath.to_str()))
 }
 
-fn get_rpaths(os: session::os, cwd: path::Path, sysroot: path::Path,
-              output: path::Path, libs: ~[path::Path],
-              target_triple: ~str) -> ~[~str] {
-    debug!("cwd: %s", cwd);
-    debug!("sysroot: %s", sysroot);
-    debug!("output: %s", output);
+fn get_rpaths(os: session::os,
+              sysroot: &Path,
+              output: &Path,
+              libs: &[Path],
+              target_triple: &str) -> ~[Path] {
+    debug!("sysroot: %s", sysroot.to_str());
+    debug!("output: %s", output.to_str());
     debug!("libs:");
     for libs.each |libpath| {
-        debug!("    %s", libpath);
+        debug!("    %s", libpath.to_str());
     }
     debug!("target_triple: %s", target_triple);
 
     // Use relative paths to the libraries. Binaries can be moved
     // as long as they maintain the relative relationship to the
     // crates they depend on.
-    let rel_rpaths = get_rpaths_relative_to_output(os, cwd, output, libs);
+    let rel_rpaths = get_rpaths_relative_to_output(os, output, libs);
 
     // Make backup absolute paths to the libraries. Binaries can
     // be moved as long as the crates they link against don't move.
-    let abs_rpaths = get_absolute_rpaths(cwd, libs);
+    let abs_rpaths = get_absolute_rpaths(libs);
 
     // And a final backup rpath to the global library location.
-    let fallback_rpaths = ~[get_install_prefix_rpath(cwd, target_triple)];
+    let fallback_rpaths = ~[get_install_prefix_rpath(target_triple)];
 
-    fn log_rpaths(desc: ~str, rpaths: ~[~str]) {
+    fn log_rpaths(desc: &str, rpaths: &[Path]) {
         debug!("%s rpaths:", desc);
         for rpaths.each |rpath| {
-            debug!("    %s", rpath);
+            debug!("    %s", rpath.to_str());
         }
     }
 
@@ -93,43 +90,37 @@ fn get_rpaths(os: session::os, cwd: path::Path, sysroot: path::Path,
 }
 
 fn get_rpaths_relative_to_output(os: session::os,
-                                 cwd: path::Path,
-                                 output: path::Path,
-                                 libs: ~[path::Path]) -> ~[~str] {
+                                 output: &Path,
+                                 libs: &[Path]) -> ~[Path] {
     vec::map(libs, |a| {
-        get_rpath_relative_to_output(os, cwd, output, a)
+        get_rpath_relative_to_output(os, output, &a)
     })
 }
 
 fn get_rpath_relative_to_output(os: session::os,
-                                cwd: path::Path,
-                                output: path::Path,
-                                &&lib: path::Path) -> ~str {
+                                output: &Path,
+                                lib: &Path) -> Path {
     assert not_win32(os);
 
     // Mac doesn't appear to support $ORIGIN
     let prefix = match os {
-        session::os_linux => ~"$ORIGIN" + path::path_sep(),
-        session::os_freebsd => ~"$ORIGIN" + path::path_sep(),
-        session::os_macos => ~"@executable_path" + path::path_sep(),
+        session::os_linux | session::os_freebsd => "$ORIGIN",
+        session::os_macos => "@executable_path",
         session::os_win32 => core::unreachable()
     };
 
-    prefix + get_relative_to(
-        get_absolute(cwd, output),
-        get_absolute(cwd, lib))
+    Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output),
+                                           &os::make_absolute(lib)))
 }
 
 // Find the relative path from one file to another
-fn get_relative_to(abs1: path::Path, abs2: path::Path) -> path::Path {
-    assert path::path_is_absolute(abs1);
-    assert path::path_is_absolute(abs2);
+fn get_relative_to(abs1: &Path, abs2: &Path) -> Path {
+    assert abs1.is_absolute;
+    assert abs2.is_absolute;
     debug!("finding relative path from %s to %s",
-           abs1, abs2);
-    let normal1 = path::normalize(abs1);
-    let normal2 = path::normalize(abs2);
-    let split1 = path::split(normal1);
-    let split2 = path::split(normal2);
+           abs1.to_str(), abs2.to_str());
+    let split1 = abs1.components;
+    let split2 = abs2.components;
     let len1 = vec::len(split1);
     let len2 = vec::len(split2);
     assert len1 > 0u;
@@ -148,48 +139,39 @@ fn get_relative_to(abs1: path::Path, abs2: path::Path) -> path::Path {
     vec::push_all(path, vec::view(split2, start_idx, len2 - 1u));
 
     if vec::is_not_empty(path) {
-        return path::connect_many(path);
+        return Path("").push_many(path);
     } else {
-        return ~".";
+        return Path(".");
     }
 }
 
-fn get_absolute_rpaths(cwd: path::Path, libs: ~[path::Path]) -> ~[~str] {
-    vec::map(libs, |a| get_absolute_rpath(cwd, a) )
+fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] {
+    vec::map(libs, |a| get_absolute_rpath(&a) )
 }
 
-fn get_absolute_rpath(cwd: path::Path, &&lib: path::Path) -> ~str {
-    path::dirname(get_absolute(cwd, lib))
+fn get_absolute_rpath(lib: &Path) -> Path {
+    os::make_absolute(lib).dir_path()
 }
 
-fn get_absolute(cwd: path::Path, lib: path::Path) -> path::Path {
-    if path::path_is_absolute(lib) {
-        lib
-    } else {
-        path::connect(cwd, lib)
-    }
-}
-
-fn get_install_prefix_rpath(cwd: path::Path, target_triple: ~str) -> ~str {
+fn get_install_prefix_rpath(target_triple: &str) -> Path {
     let install_prefix = env!("CFG_PREFIX");
 
     if install_prefix == ~"" {
         fail ~"rustc compiled without CFG_PREFIX environment variable";
     }
 
-    let path = vec::append(
-        ~[install_prefix],
-        filesearch::relative_target_lib_path(target_triple));
-    get_absolute(cwd, path::connect_many(path))
+    let tlib = filesearch::relative_target_lib_path(target_triple);
+    os::make_absolute(&Path(install_prefix).push_rel(&tlib))
 }
 
-fn minimize_rpaths(rpaths: ~[~str]) -> ~[~str] {
+fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] {
     let set = map::str_hash::<()>();
     let mut minimized = ~[];
     for rpaths.each |rpath| {
-        if !set.contains_key(rpath) {
+        let s = rpath.to_str();
+        if !set.contains_key(s) {
             vec::push(minimized, rpath);
-            set.insert(rpath, ());
+            set.insert(s, ());
         }
     }
     return minimized;
@@ -199,116 +181,112 @@ fn minimize_rpaths(rpaths: ~[~str]) -> ~[~str] {
 mod test {
     #[test]
     fn test_rpaths_to_flags() {
-        let flags = rpaths_to_flags(~[~"path1", ~"path2"]);
+        let flags = rpaths_to_flags(~[Path("path1"),
+                                      Path("path2")]);
         assert flags == ~[~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"];
     }
 
     #[test]
-    fn test_get_absolute1() {
-        let cwd = ~"/dir";
-        let lib = ~"some/path/lib";
-        let res = get_absolute(cwd, lib);
-        assert res == ~"/dir/some/path/lib";
-    }
-
-    #[test]
-    fn test_get_absolute2() {
-        let cwd = ~"/dir";
-        let lib = ~"/some/path/lib";
-        let res = get_absolute(cwd, lib);
-        assert res == ~"/some/path/lib";
-    }
-
-    #[test]
     fn test_prefix_rpath() {
-        let res = get_install_prefix_rpath(~"/usr/lib", ~"triple");
-        let d = path::connect(env!("CFG_PREFIX"), ~"/lib/rustc/triple/lib");
-        assert str::ends_with(res, d);
+        let res = get_install_prefix_rpath("triple");
+        let d = Path(env!("CFG_PREFIX"))
+            .push_rel(&Path("lib/rustc/triple/lib"));
+        debug!("test_prefix_path: %s vs. %s",
+               res.to_str(),
+               d.to_str());
+        assert str::ends_with(res.to_str(), d.to_str());
     }
 
     #[test]
     fn test_prefix_rpath_abs() {
-        let res = get_install_prefix_rpath(~"/usr/lib", ~"triple");
-        assert path::path_is_absolute(res);
+        let res = get_install_prefix_rpath("triple");
+        assert res.is_absolute;
     }
 
     #[test]
     fn test_minimize1() {
-        let res = minimize_rpaths(~[~"rpath1", ~"rpath2", ~"rpath1"]);
-        assert res == ~[~"rpath1", ~"rpath2"];
+        let res = minimize_rpaths([Path("rpath1"),
+                                   Path("rpath2"),
+                                   Path("rpath1")]);
+        assert res == ~[Path("rpath1"), Path("rpath2")];
     }
 
     #[test]
     fn test_minimize2() {
-        let res = minimize_rpaths(~[~"1a", ~"2", ~"2", ~"1a", ~"4a",
-                                   ~"1a", ~"2", ~"3", ~"4a", ~"3"]);
-        assert res == ~[~"1a", ~"2", ~"4a", ~"3"];
+        let res = minimize_rpaths(~[Path("1a"), Path("2"), Path("2"),
+                                    Path("1a"), Path("4a"),Path("1a"),
+                                    Path("2"), Path("3"), Path("4a"),
+                                    Path("3")]);
+        assert res == ~[Path("1a"), Path("2"), Path("4a"), Path("3")];
     }
 
     #[test]
     fn test_relative_to1() {
-        let p1 = ~"/usr/bin/rustc";
-        let p2 = ~"/usr/lib/mylib";
-        let res = get_relative_to(p1, p2);
-        assert res == ~"../lib";
+        let p1 = Path("/usr/bin/rustc");
+        let p2 = Path("/usr/lib/mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../lib");
     }
 
     #[test]
     fn test_relative_to2() {
-        let p1 = ~"/usr/bin/rustc";
-        let p2 = ~"/usr/bin/../lib/mylib";
-        let res = get_relative_to(p1, p2);
-        assert res == ~"../lib";
+        let p1 = Path("/usr/bin/rustc");
+        let p2 = Path("/usr/bin/../lib/mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../lib");
     }
 
     #[test]
     fn test_relative_to3() {
-        let p1 = ~"/usr/bin/whatever/rustc";
-        let p2 = ~"/usr/lib/whatever/mylib";
-        let res = get_relative_to(p1, p2);
-        assert res == ~"../../lib/whatever";
+        let p1 = Path("/usr/bin/whatever/rustc");
+        let p2 = Path("/usr/lib/whatever/mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../../lib/whatever");
     }
 
     #[test]
     fn test_relative_to4() {
-        let p1 = ~"/usr/bin/whatever/../rustc";
-        let p2 = ~"/usr/lib/whatever/mylib";
-        let res = get_relative_to(p1, p2);
-        assert res == ~"../lib/whatever";
+        let p1 = Path("/usr/bin/whatever/../rustc");
+        let p2 = Path("/usr/lib/whatever/mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../lib/whatever");
     }
 
     #[test]
     fn test_relative_to5() {
-        let p1 = ~"/usr/bin/whatever/../rustc";
-        let p2 = ~"/usr/lib/whatever/../mylib";
-        let res = get_relative_to(p1, p2);
-        assert res == ~"../lib";
+        let p1 = Path("/usr/bin/whatever/../rustc");
+        let p2 = Path("/usr/lib/whatever/../mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../lib");
     }
 
     #[test]
     fn test_relative_to6() {
-        let p1 = ~"/1";
-        let p2 = ~"/2/3";
-        let res = get_relative_to(p1, p2);
-        assert res == ~"2";
+        let p1 = Path("/1");
+        let p2 = Path("/2/3");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("2");
     }
 
     #[test]
     fn test_relative_to7() {
-        let p1 = ~"/1/2";
-        let p2 = ~"/3";
-        let res = get_relative_to(p1, p2);
-        assert res == ~"..";
+        let p1 = Path("/1/2");
+        let p2 = Path("/3");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("..");
     }
 
     #[test]
     fn test_relative_to8() {
-        let p1 = ~"/home/brian/Dev/rust/build/"
-            + ~"stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
-        let p2 = ~"/home/brian/Dev/rust/build/stage2/bin/.."
-            + ~"/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
-        let res = get_relative_to(p1, p2);
-        assert res == ~".";
+        let p1 = Path("/home/brian/Dev/rust/build/").push_rel(
+            &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so"));
+        let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel(
+            &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so"));
+        let res = get_relative_to(&p1, &p2);
+        debug!("test_relative_tu8: %s vs. %s",
+               res.to_str(),
+               Path(".").to_str());
+        assert res == Path(".");
     }
 
     #[test]
@@ -316,8 +294,8 @@ mod test {
     fn test_rpath_relative() {
       let o = session::os_linux;
       let res = get_rpath_relative_to_output(o,
-            ~"/usr", ~"bin/rustc", ~"lib/libstd.so");
-      assert res == ~"$ORIGIN/../lib";
+            &Path("bin/rustc"), &Path("lib/libstd.so"));
+      assert res == Path("$ORIGIN/../lib");
     }
 
     #[test]
@@ -325,8 +303,8 @@ mod test {
     fn test_rpath_relative() {
         let o = session::os_freebsd;
         let res = get_rpath_relative_to_output(o,
-            ~"/usr", ~"bin/rustc", ~"lib/libstd.so");
-        assert res == ~"$ORIGIN/../lib";
+            &Path("bin/rustc"), &Path("lib/libstd.so"));
+        assert res == Path("$ORIGIN/../lib");
     }
 
     #[test]
@@ -334,14 +312,19 @@ mod test {
     fn test_rpath_relative() {
         // this is why refinements would be nice
         let o = session::os_macos;
-        let res = get_rpath_relative_to_output(o, ~"/usr", ~"bin/rustc",
-                                               ~"lib/libstd.so");
-        assert res == ~"@executable_path/../lib";
+        let res = get_rpath_relative_to_output(o,
+                                               &Path("bin/rustc"),
+                                               &Path("lib/libstd.so"));
+        assert res == Path("@executable_path/../lib");
     }
 
     #[test]
     fn test_get_absolute_rpath() {
-        let res = get_absolute_rpath(~"/usr", ~"lib/libstd.so");
-        assert res == ~"/usr/lib";
+        let res = get_absolute_rpath(&Path("lib/libstd.so"));
+        debug!("test_get_absolute_rpath: %s vs. %s",
+               res.to_str(),
+               os::make_absolute(&Path("lib")).to_str());
+
+        assert res == os::make_absolute(&Path("lib"));
     }
 }
diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs
index 087c6c3b833..c1a371af4dd 100644
--- a/src/rustc/driver/driver.rs
+++ b/src/rustc/driver/driver.rs
@@ -27,7 +27,7 @@ fn anon_src() -> ~str { ~"<anon>" }
 
 fn source_name(input: input) -> ~str {
     match input {
-      file_input(ifile) => ifile,
+      file_input(ifile) => ifile.to_str(),
       str_input(_) => anon_src()
     }
 }
@@ -92,7 +92,7 @@ fn parse_cfgspecs(cfgspecs: ~[~str]) -> ast::crate_cfg {
 
 enum input {
     /// Load source from file
-    file_input(~str),
+    file_input(Path),
     /// The string is the source
     str_input(~str)
 }
@@ -101,7 +101,7 @@ fn parse_input(sess: session, cfg: ast::crate_cfg, input: input)
     -> @ast::crate {
     match input {
       file_input(file) => {
-        parse::parse_crate_from_file(file, cfg, sess.parse_sess)
+        parse::parse_crate_from_file(&file, cfg, sess.parse_sess)
       }
       str_input(src) => {
         // FIXME (#2319): Don't really want to box the source string
@@ -236,11 +236,13 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
                 vtable_map: vtable_map};
 
     let (llmod, link_meta) = time(time_passes, ~"translation", ||
-        trans::base::trans_crate(sess, crate, ty_cx, outputs.obj_filename,
+        trans::base::trans_crate(sess, crate, ty_cx,
+                                 &outputs.obj_filename,
                                  exp_map, exp_map2, maps));
 
     time(time_passes, ~"LLVM passes", ||
-        link::write::run_passes(sess, llmod, outputs.obj_filename));
+        link::write::run_passes(sess, llmod,
+                                &outputs.obj_filename));
 
     let stop_after_codegen =
         sess.opts.output_type != link::output_type_exe ||
@@ -249,14 +251,15 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
     if stop_after_codegen { return {crate: crate, tcx: some(ty_cx)}; }
 
     time(time_passes, ~"linking", ||
-         link::link_binary(sess, outputs.obj_filename,
-                           outputs.out_filename, link_meta));
+         link::link_binary(sess,
+                           &outputs.obj_filename,
+                           &outputs.out_filename, link_meta));
 
     return {crate: crate, tcx: some(ty_cx)};
 }
 
 fn compile_input(sess: session, cfg: ast::crate_cfg, input: input,
-                 outdir: option<~str>, output: option<~str>) {
+                 outdir: &option<Path>, output: &option<Path>) {
 
     let upto = if sess.opts.parse_only { cu_parse }
                else if sess.opts.no_trans { cu_no_trans }
@@ -483,6 +486,7 @@ fn build_session_options(matches: getopts::matches,
     let extra_debuginfo = opt_present(matches, ~"xg");
     let debuginfo = opt_present(matches, ~"g") || extra_debuginfo;
     let sysroot_opt = getopts::opt_maybe_str(matches, ~"sysroot");
+    let sysroot_opt = option::map(sysroot_opt, |m| Path(m));
     let target_opt = getopts::opt_maybe_str(matches, ~"target");
     let save_temps = getopts::opt_present(matches, ~"save-temps");
     match output_type {
@@ -514,7 +518,9 @@ fn build_session_options(matches: getopts::matches,
             some(s) => s
         };
 
-    let addl_lib_search_paths = getopts::opt_strs(matches, ~"L");
+    let addl_lib_search_paths =
+        getopts::opt_strs(matches, ~"L")
+        .map(|s| Path(s));
     let cfg = parse_cfgspecs(getopts::opt_strs(matches, ~"cfg"));
     let test = opt_present(matches, ~"test");
     let sopts: @session::options =
@@ -614,11 +620,11 @@ fn opts() -> ~[getopts::opt] {
           optflag(~"static"), optflag(~"gc")];
 }
 
-type output_filenames = @{out_filename: ~str, obj_filename:~str};
+type output_filenames = @{out_filename:Path, obj_filename:Path};
 
 fn build_output_filenames(input: input,
-                          odir: option<~str>,
-                          ofile: option<~str>,
+                          odir: &option<Path>,
+                          ofile: &option<Path>,
                           sess: session)
         -> output_filenames {
     let obj_path;
@@ -639,37 +645,30 @@ fn build_output_filenames(input: input,
           link::output_type_object | link::output_type_exe => ~"o"
         };
 
-    match ofile {
+    match *ofile {
       none => {
         // "-" as input file will cause the parser to read from stdin so we
         // have to make up a name
         // We want to toss everything after the final '.'
-        let dirname = match odir {
+        let dirpath = match *odir {
           some(d) => d,
           none => match input {
             str_input(_) => os::getcwd(),
-            file_input(ifile) => path::dirname(ifile)
+            file_input(ifile) => ifile.dir_path()
           }
         };
 
-        let base_filename = match input {
-          file_input(ifile) => {
-            let (path, _) = path::splitext(ifile);
-            path::basename(path)
-          }
+        let stem = match input {
+          file_input(ifile) => option::get(ifile.filestem()),
           str_input(_) => ~"rust_out"
         };
-        let base_path = path::connect(dirname, base_filename);
-
 
         if sess.building_library {
-            let basename = path::basename(base_path);
-            let dylibname = os::dll_filename(basename);
-            out_path = path::connect(dirname, dylibname);
-            obj_path = path::connect(dirname, basename + ~"." + obj_suffix);
+            out_path = dirpath.push(os::dll_filename(stem));
+            obj_path = dirpath.push(stem).with_filetype(obj_suffix);
         } else {
-            out_path = base_path;
-            obj_path = base_path + ~"." + obj_suffix;
+            out_path = dirpath.push(stem);
+            obj_path = dirpath.push(stem).with_filetype(obj_suffix);
         }
       }
 
@@ -678,9 +677,7 @@ fn build_output_filenames(input: input,
         obj_path = if stop_after_codegen {
             out_file
         } else {
-            let (base, _) = path::splitext(out_file);
-            let modified = base + ~"." + obj_suffix;
-            modified
+            out_file.with_filetype(obj_suffix)
         };
 
         if sess.building_library {
@@ -690,13 +687,13 @@ fn build_output_filenames(input: input,
             // lib<basename>-<hash>-<version>.so no matter what.
         }
 
-        if odir != none {
+        if *odir != none {
             sess.warn(~"ignoring --out-dir flag due to -o flag.");
         }
       }
     }
     return @{out_filename: out_path,
-          obj_filename: obj_path};
+             obj_filename: obj_path};
 }
 
 fn early_error(emitter: diagnostic::emitter, msg: ~str) -> ! {
@@ -704,7 +701,7 @@ fn early_error(emitter: diagnostic::emitter, msg: ~str) -> ! {
     fail;
 }
 
-fn list_metadata(sess: session, path: ~str, out: io::Writer) {
+fn list_metadata(sess: session, path: &Path, out: io::Writer) {
     metadata::loader::list_file_metadata(
         sess.parse_sess.interner,
         session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
diff --git a/src/rustc/driver/rustc.rs b/src/rustc/driver/rustc.rs
index 0770a132a1d..e26465fce5d 100644
--- a/src/rustc/driver/rustc.rs
+++ b/src/rustc/driver/rustc.rs
@@ -159,7 +159,7 @@ fn run_compiler(args: ~[~str], demitter: diagnostic::emitter) {
             let src = str::from_bytes(io::stdin().read_whole_stream());
             str_input(src)
         } else {
-            file_input(ifile)
+            file_input(Path(ifile))
         }
       }
       _ => early_error(demitter, ~"multiple input filenames provided")
@@ -168,7 +168,9 @@ fn run_compiler(args: ~[~str], demitter: diagnostic::emitter) {
     let sopts = build_session_options(matches, demitter);
     let sess = build_session(sopts, demitter);
     let odir = getopts::opt_maybe_str(matches, ~"out-dir");
+    let odir = option::map(odir, |o| Path(o));
     let ofile = getopts::opt_maybe_str(matches, ~"o");
+    let ofile = option::map(ofile, |o| Path(o));
     let cfg = build_configuration(sess, binary, input);
     let pretty =
         option::map(getopts::opt_default(matches, ~"pretty",
@@ -185,7 +187,7 @@ fn run_compiler(args: ~[~str], demitter: diagnostic::emitter) {
     if ls {
         match input {
           file_input(ifile) => {
-            list_metadata(sess, ifile, io::stdout());
+            list_metadata(sess, &ifile, io::stdout());
           }
           str_input(_) => {
             early_error(demitter, ~"can not list metadata for stdin");
@@ -194,7 +196,7 @@ fn run_compiler(args: ~[~str], demitter: diagnostic::emitter) {
         return;
     }
 
-    compile_input(sess, cfg, input, odir, ofile);
+    compile_input(sess, cfg, input, &odir, &ofile);
 }
 
 /*
diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs
index cd663c06ce7..10c0f283525 100644
--- a/src/rustc/driver/session.rs
+++ b/src/rustc/driver/session.rs
@@ -89,8 +89,8 @@ type options =
      lint_opts: ~[(lint::lint, lint::level)],
      save_temps: bool,
      output_type: back::link::output_type,
-     addl_lib_search_paths: ~[~str],
-     maybe_sysroot: option<~str>,
+     addl_lib_search_paths: ~[Path],
+     maybe_sysroot: option<Path>,
      target_triple: ~str,
      cfg: ast::crate_cfg,
      test: bool,
@@ -111,7 +111,7 @@ type session_ = {targ_cfg: @config,
                  span_diagnostic: diagnostic::span_handler,
                  filesearch: filesearch::filesearch,
                  mut building_library: bool,
-                 working_dir: ~str,
+                 working_dir: Path,
                  lint_settings: lint::lint_settings};
 
 enum session {
diff --git a/src/rustc/metadata/creader.rs b/src/rustc/metadata/creader.rs
index 5867dc12672..685717e8e8d 100644
--- a/src/rustc/metadata/creader.rs
+++ b/src/rustc/metadata/creader.rs
@@ -199,7 +199,7 @@ fn resolve_crate(e: env, ident: ast::ident, metas: ~[@ast::meta_item],
         };
         let cinfo = loader::load_library_crate(load_ctxt);
 
-        let cfilename = cinfo.ident;
+        let cfilename = Path(cinfo.ident);
         let cdata = cinfo.data;
 
         let attrs = decoder::get_crate_attributes(cdata);
@@ -225,7 +225,7 @@ fn resolve_crate(e: env, ident: ast::ident, metas: ~[@ast::meta_item],
 
         let cstore = e.cstore;
         cstore::set_crate_data(cstore, cnum, cmeta);
-        cstore::add_used_crate_file(cstore, cfilename);
+        cstore::add_used_crate_file(cstore, &cfilename);
         return cnum;
       }
       some(cnum) => {
diff --git a/src/rustc/metadata/cstore.rs b/src/rustc/metadata/cstore.rs
index 4b65953781a..d2cab8c3177 100644
--- a/src/rustc/metadata/cstore.rs
+++ b/src/rustc/metadata/cstore.rs
@@ -56,7 +56,7 @@ type cstore_private =
     @{metas: map::hashmap<ast::crate_num, crate_metadata>,
       use_crate_map: use_crate_map,
       mod_path_map: mod_path_map,
-      mut used_crate_files: ~[~str],
+      mut used_crate_files: ~[Path],
       mut used_libraries: ~[~str],
       mut used_link_args: ~[~str],
       intr: ident_interner};
@@ -114,13 +114,13 @@ fn iter_crate_data(cstore: cstore, i: fn(ast::crate_num, crate_metadata)) {
     for p(cstore).metas.each |k,v| { i(k, v);};
 }
 
-fn add_used_crate_file(cstore: cstore, lib: ~str) {
-    if !vec::contains(p(cstore).used_crate_files, lib) {
-        vec::push(p(cstore).used_crate_files, lib);
+fn add_used_crate_file(cstore: cstore, lib: &Path) {
+    if !vec::contains(p(cstore).used_crate_files, copy *lib) {
+        vec::push(p(cstore).used_crate_files, copy *lib);
     }
 }
 
-fn get_used_crate_files(cstore: cstore) -> ~[~str] {
+fn get_used_crate_files(cstore: cstore) -> ~[Path] {
     return p(cstore).used_crate_files;
 }
 
diff --git a/src/rustc/metadata/filesearch.rs b/src/rustc/metadata/filesearch.rs
index 72661891163..de0c31b9c3d 100644
--- a/src/rustc/metadata/filesearch.rs
+++ b/src/rustc/metadata/filesearch.rs
@@ -14,12 +14,10 @@ export get_cargo_root;
 export get_cargo_root_nearest;
 export libdir;
 
-import path::Path;
+type pick<T> = fn(path: &Path) -> option<T>;
 
-type pick<T> = fn(path: Path) -> option<T>;
-
-fn pick_file(file: Path, path: Path) -> option<Path> {
-    if path::basename(path) == file { option::some(path) }
+fn pick_file(file: Path, path: &Path) -> option<Path> {
+    if path.file_path() == file { option::some(copy *path) }
     else { option::none }
 }
 
@@ -27,11 +25,11 @@ trait filesearch {
     fn sysroot() -> Path;
     fn lib_search_paths() -> ~[Path];
     fn get_target_lib_path() -> Path;
-    fn get_target_lib_file_path(file: Path) -> Path;
+    fn get_target_lib_file_path(file: &Path) -> Path;
 }
 
 fn mk_filesearch(maybe_sysroot: option<Path>,
-                 target_triple: ~str,
+                 target_triple: &str,
                  addl_lib_search_paths: ~[Path]) -> filesearch {
     type filesearch_impl = {sysroot: Path,
                             addl_lib_search_paths: ~[Path],
@@ -42,7 +40,8 @@ fn mk_filesearch(maybe_sysroot: option<Path>,
             let mut paths = self.addl_lib_search_paths;
 
             vec::push(paths,
-                      make_target_lib_path(self.sysroot, self.target_triple));
+                      make_target_lib_path(&self.sysroot,
+                                           self.target_triple));
             match get_cargo_lib_path_nearest() {
               result::ok(p) => vec::push(paths, p),
               result::err(p) => ()
@@ -54,33 +53,33 @@ fn mk_filesearch(maybe_sysroot: option<Path>,
             paths
         }
         fn get_target_lib_path() -> Path {
-            make_target_lib_path(self.sysroot, self.target_triple)
+            make_target_lib_path(&self.sysroot, self.target_triple)
         }
-        fn get_target_lib_file_path(file: Path) -> Path {
-            path::connect(self.get_target_lib_path(), file)
+        fn get_target_lib_file_path(file: &Path) -> Path {
+            self.get_target_lib_path().push_rel(file)
         }
     }
 
     let sysroot = get_sysroot(maybe_sysroot);
-    debug!("using sysroot = %s", sysroot);
+    debug!("using sysroot = %s", sysroot.to_str());
     {sysroot: sysroot,
      addl_lib_search_paths: addl_lib_search_paths,
-     target_triple: target_triple} as filesearch
+     target_triple: str::from_slice(target_triple)} as filesearch
 }
 
 fn search<T: copy>(filesearch: filesearch, pick: pick<T>) -> option<T> {
     let mut rslt = none;
     for filesearch.lib_search_paths().each |lib_search_path| {
-        debug!("searching %s", lib_search_path);
-        for os::list_dir_path(lib_search_path).each |path| {
-            debug!("testing %s", path);
+        debug!("searching %s", lib_search_path.to_str());
+        for os::list_dir_path(&lib_search_path).each |path| {
+            debug!("testing %s", path.to_str());
             let maybe_picked = pick(path);
             if option::is_some(maybe_picked) {
-                debug!("picked %s", path);
+                debug!("picked %s", path.to_str());
                 rslt = maybe_picked;
                 break;
             } else {
-                debug!("rejected %s", path);
+                debug!("rejected %s", path.to_str());
             }
         }
         if option::is_some(rslt) { break; }
@@ -88,21 +87,20 @@ fn search<T: copy>(filesearch: filesearch, pick: pick<T>) -> option<T> {
     return rslt;
 }
 
-fn relative_target_lib_path(target_triple: ~str) -> ~[Path] {
-    ~[libdir(), ~"rustc", target_triple, libdir()]
+fn relative_target_lib_path(target_triple: &str) -> Path {
+    Path(libdir()).push_many([~"rustc",
+                              str::from_slice(target_triple),
+                              libdir()])
 }
 
-fn make_target_lib_path(sysroot: Path,
-                        target_triple: ~str) -> Path {
-    let path = vec::append(~[sysroot],
-                           relative_target_lib_path(target_triple));
-    let path = path::connect_many(path);
-    return path;
+fn make_target_lib_path(sysroot: &Path,
+                        target_triple: &str) -> Path {
+    sysroot.push_rel(&relative_target_lib_path(target_triple))
 }
 
 fn get_default_sysroot() -> Path {
     match os::self_exe_path() {
-      option::some(p) => path::normalize(path::connect(p, ~"..")),
+      option::some(p) => p.pop(),
       option::none => fail ~"can't determine value for sysroot"
     }
 }
@@ -115,15 +113,14 @@ fn get_sysroot(maybe_sysroot: option<Path>) -> Path {
 }
 
 fn get_cargo_sysroot() -> result<Path, ~str> {
-    let path = ~[get_default_sysroot(), libdir(), ~"cargo"];
-    result::ok(path::connect_many(path))
+    result::ok(get_default_sysroot().push_many([libdir(), ~"cargo"]))
 }
 
 fn get_cargo_root() -> result<Path, ~str> {
     match os::getenv(~"CARGO_ROOT") {
-        some(_p) => result::ok(_p),
+        some(_p) => result::ok(Path(_p)),
         none => match os::homedir() {
-          some(_q) => result::ok(path::connect(_q, ~".cargo")),
+          some(_q) => result::ok(_q.push(".cargo")),
           none => result::err(~"no CARGO_ROOT or home directory")
         }
     }
@@ -132,21 +129,21 @@ fn get_cargo_root() -> result<Path, ~str> {
 fn get_cargo_root_nearest() -> result<Path, ~str> {
     do result::chain(get_cargo_root()) |p| {
         let cwd = os::getcwd();
-        let mut dirname = path::dirname(cwd);
-        let mut dirpath = path::split(dirname);
-        let cwd_cargo = path::connect(cwd, ~".cargo");
-        let mut par_cargo = path::connect(dirname, ~".cargo");
+        let cwd_cargo = cwd.push(".cargo");
+        let mut par_cargo = cwd.pop().push(".cargo");
         let mut rslt = result::ok(cwd_cargo);
 
-        if !os::path_is_dir(cwd_cargo) && cwd_cargo != p {
-            while vec::is_not_empty(dirpath) && par_cargo != p {
-                if os::path_is_dir(par_cargo) {
+        if !os::path_is_dir(&cwd_cargo) && cwd_cargo != p {
+            while par_cargo != p {
+                if os::path_is_dir(&par_cargo) {
                     rslt = result::ok(par_cargo);
                     break;
                 }
-                vec::pop(dirpath);
-                dirname = path::dirname(dirname);
-                par_cargo = path::connect(dirname, ~".cargo");
+                if par_cargo.components.len() == 1 {
+                    // We just checked /.cargo, stop now.
+                    break;
+                }
+                par_cargo = par_cargo.pop().pop().push(".cargo");
             }
         }
         rslt
@@ -155,13 +152,13 @@ fn get_cargo_root_nearest() -> result<Path, ~str> {
 
 fn get_cargo_lib_path() -> result<Path, ~str> {
     do result::chain(get_cargo_root()) |p| {
-        result::ok(path::connect(p, libdir()))
+        result::ok(p.push(libdir()))
     }
 }
 
 fn get_cargo_lib_path_nearest() -> result<Path, ~str> {
     do result::chain(get_cargo_root_nearest()) |p| {
-        result::ok(path::connect(p, libdir()))
+        result::ok(p.push(libdir()))
     }
 }
 
diff --git a/src/rustc/metadata/loader.rs b/src/rustc/metadata/loader.rs
index f010b7e9754..513b4dd4216 100644
--- a/src/rustc/metadata/loader.rs
+++ b/src/rustc/metadata/loader.rs
@@ -74,27 +74,28 @@ fn find_library_crate_aux(cx: ctxt,
 
     let mut matches = ~[];
     filesearch::search(filesearch, |path| {
-        debug!("inspecting file %s", path);
-        let f: ~str = path::basename(path);
+        debug!("inspecting file %s", path.to_str());
+        let f: ~str = option::get(path.filename());
         if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) {
-            debug!("skipping %s, doesn't look like %s*%s", path, prefix,
-                   suffix);
+            debug!("skipping %s, doesn't look like %s*%s", path.to_str(),
+                   prefix, suffix);
             option::none::<()>
         } else {
-            debug!("%s is a candidate", path);
+            debug!("%s is a candidate", path.to_str());
             match get_metadata_section(cx.os, path) {
               option::some(cvec) => {
                 if !crate_matches(cvec, cx.metas, cx.hash) {
-                    debug!("skipping %s, metadata doesn't match", path);
+                    debug!("skipping %s, metadata doesn't match",
+                           path.to_str());
                     option::none::<()>
                 } else {
-                    debug!("found %s with matching metadata", path);
-                    vec::push(matches, {ident: path, data: cvec});
+                    debug!("found %s with matching metadata", path.to_str());
+                    vec::push(matches, {ident: path.to_str(), data: cvec});
                     option::none::<()>
                 }
               }
               _ => {
-                debug!("could not load metadata for %s", path);
+                debug!("could not load metadata for %s", path.to_str());
                 option::none::<()>
               }
             }
@@ -168,10 +169,10 @@ fn metadata_matches(extern_metas: ~[@ast::meta_item],
 }
 
 fn get_metadata_section(os: os,
-                        filename: ~str) -> option<@~[u8]> unsafe {
-    let mb = str::as_c_str(filename, |buf| {
+                        filename: &Path) -> option<@~[u8]> unsafe {
+    let mb = str::as_c_str(filename.to_str(), |buf| {
         llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
-                                   });
+    });
     if mb as int == 0 { return option::none::<@~[u8]>; }
     let of = match mk_object_file(mb) {
         option::some(of) => of,
@@ -204,12 +205,13 @@ fn meta_section_name(os: os) -> ~str {
 }
 
 // A diagnostic function for dumping crate metadata to an output stream
-fn list_file_metadata(intr: ident_interner, os: os, path: ~str,
-                      out: io::Writer) {
+fn list_file_metadata(intr: ident_interner,
+                      os: os, path: &Path, out: io::Writer) {
     match get_metadata_section(os, path) {
       option::some(bytes) => decoder::list_crate_metadata(intr, bytes, out),
       option::none => {
-        out.write_str(~"could not find metadata in " + path + ~".\n");
+        out.write_str(~"could not find metadata in "
+                      + path.to_str() + ~".\n");
       }
     }
 }
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index dddcdd64da3..fe0d49a3532 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -5778,7 +5778,7 @@ fn write_abi_version(ccx: @crate_ctxt) {
 fn trans_crate(sess: session::session,
                crate: @ast::crate,
                tcx: ty::ctxt,
-               output: ~str,
+               output: &Path,
                emap: resolve3::ExportMap,
                emap2: resolve3::ExportMap2,
                maps: astencode::maps)
diff --git a/src/rustc/middle/trans/debuginfo.rs b/src/rustc/middle/trans/debuginfo.rs
index 04e0f7be75f..42b8274d78c 100644
--- a/src/rustc/middle/trans/debuginfo.rs
+++ b/src/rustc/middle/trans/debuginfo.rs
@@ -172,7 +172,7 @@ fn create_compile_unit(cx: @crate_ctxt)
       option::none => ()
     }
 
-    let (_, work_dir) = get_file_path_and_dir(cx.sess.working_dir,
+    let (_, work_dir) = get_file_path_and_dir(cx.sess.working_dir.to_str(),
                                               crate_name);
     let unit_metadata = ~[lltag(tg),
                          llunused(),
@@ -197,13 +197,13 @@ fn get_cache(cx: @crate_ctxt) -> metadata_cache {
     option::get(cx.dbg_cx).llmetadata
 }
 
-fn get_file_path_and_dir(work_dir: ~str, full_path: ~str) -> (~str, ~str) {
+fn get_file_path_and_dir(work_dir: &str, full_path: &str) -> (~str, ~str) {
     (if str::starts_with(full_path, work_dir) {
         str::slice(full_path, str::len(work_dir) + 1u,
                    str::len(full_path))
     } else {
-        full_path
-    }, work_dir)
+        str::from_slice(full_path)
+    }, str::from_slice(work_dir))
 }
 
 fn create_file(cx: @crate_ctxt, full_path: ~str) -> @metadata<file_md> {
@@ -215,8 +215,9 @@ fn create_file(cx: @crate_ctxt, full_path: ~str) -> @metadata<file_md> {
         option::none => ()
     }
 
-    let (file_path, work_dir) = get_file_path_and_dir(cx.sess.working_dir,
-                                                      full_path);
+    let (file_path, work_dir) =
+        get_file_path_and_dir(cx.sess.working_dir.to_str(),
+                              full_path);
     let unit_node = create_compile_unit(cx).node;
     let file_md = ~[lltag(tg),
                    llstr(file_path),
diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs
index 1634d38577e..9d952517052 100644
--- a/src/rustc/util/ppaux.rs
+++ b/src/rustc/util/ppaux.rs
@@ -210,6 +210,9 @@ fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str {
       ty::vstore_fixed(_) => {
         fmt!("%s/%s", ty, vstore_to_str(cx, vs))
       }
+      ty::vstore_slice(_) => {
+        fmt!("%s/%s", vstore_to_str(cx, vs), ty)
+      }
       _ => fmt!("%s%s", vstore_to_str(cx, vs), ty)
     }
 }
diff --git a/src/rustdoc/astsrv.rs b/src/rustdoc/astsrv.rs
index 3dd029f2307..91f910f5280 100644
--- a/src/rustdoc/astsrv.rs
+++ b/src/rustdoc/astsrv.rs
@@ -51,7 +51,7 @@ fn from_str<T>(source: ~str, owner: srv_owner<T>) -> T {
 }
 
 fn from_file<T>(file: ~str, owner: srv_owner<T>) -> T {
-    run(owner, file, parse::from_file_sess)
+    run(owner, file, |sess, f| parse::from_file_sess(sess, &Path(f)))
 }
 
 fn run<T>(owner: srv_owner<T>, source: ~str, +parse: parser) -> T {
diff --git a/src/rustdoc/config.rs b/src/rustdoc/config.rs
index 96f418247af..9bb3d4730d4 100644
--- a/src/rustdoc/config.rs
+++ b/src/rustdoc/config.rs
@@ -28,8 +28,8 @@ enum output_style {
 
 /// The configuration for a rustdoc session
 type config = {
-    input_crate: ~str,
-    output_dir: ~str,
+    input_crate: Path,
+    output_dir: Path,
     output_format: output_format,
     output_style: output_style,
     pandoc_cmd: option<~str>
@@ -67,10 +67,10 @@ fn usage() {
     println(~"");
 }
 
-fn default_config(input_crate: ~str) -> config {
+fn default_config(input_crate: &Path) -> config {
     {
-        input_crate: input_crate,
-        output_dir: ~".",
+        input_crate: *input_crate,
+        output_dir: Path("."),
         output_format: pandoc_html,
         output_style: doc_per_mod,
         pandoc_cmd: none
@@ -103,8 +103,8 @@ fn parse_config_(
     match getopts::getopts(args, opts) {
         result::ok(matches) => {
             if vec::len(matches.free) == 1u {
-                let input_crate = vec::head(matches.free);
-                config_from_opts(input_crate, matches, program_output)
+                let input_crate = Path(vec::head(matches.free));
+                config_from_opts(&input_crate, matches, program_output)
             } else if vec::is_empty(matches.free) {
                 result::err(~"no crates specified")
             } else {
@@ -118,7 +118,7 @@ fn parse_config_(
 }
 
 fn config_from_opts(
-    input_crate: ~str,
+    input_crate: &Path,
     matches: getopts::matches,
     program_output: program_output
 ) -> result<config, ~str> {
@@ -127,6 +127,7 @@ fn config_from_opts(
     let result = result::ok(config);
     let result = do result::chain(result) |config| {
         let output_dir = getopts::opt_maybe_str(matches, opt_output_dir());
+        let output_dir = option::map(output_dir, |s| Path(s));
         result::ok({
             output_dir: option::get_default(output_dir, config.output_dir)
             with config
@@ -205,7 +206,7 @@ fn maybe_find_pandoc(
       none => {
         ~[~"pandoc"] + match os::homedir() {
           some(dir) => {
-            ~[path::connect(dir, ~".cabal/bin/pandoc")]
+            ~[dir.push_rel(&Path(".cabal/bin/pandoc")).to_str()]
           }
           none => ~[]
         }
@@ -229,7 +230,7 @@ fn maybe_find_pandoc(
 fn should_find_pandoc() {
     let config = {
         output_format: pandoc_html
-        with default_config(~"test")
+        with default_config(&Path("test"))
     };
     let mock_program_output = fn~(_prog: &str, _args: &[~str]) -> {
         status: int, out: ~str, err: ~str
@@ -246,7 +247,7 @@ fn should_find_pandoc() {
 fn should_error_with_no_pandoc() {
     let config = {
         output_format: pandoc_html
-        with default_config(~"test")
+        with default_config(&Path("test"))
     };
     let mock_program_output = fn~(_prog: &str, _args: &[~str]) -> {
         status: int, out: ~str, err: ~str
@@ -282,7 +283,7 @@ fn should_error_with_multiple_crates() {
 #[test]
 fn should_set_output_dir_to_cwd_if_not_provided() {
     let config = test::parse_config(~[~"rustdoc", ~"crate.rc"]);
-    assert result::get(config).output_dir == ~".";
+    assert result::get(config).output_dir == Path(".");
 }
 
 #[test]
@@ -290,7 +291,7 @@ fn should_set_output_dir_if_provided() {
     let config = test::parse_config(~[
         ~"rustdoc", ~"crate.rc", ~"--output-dir", ~"snuggles"
     ]);
-    assert result::get(config).output_dir == ~"snuggles";
+    assert result::get(config).output_dir == Path("snuggles");
 }
 
 #[test]
diff --git a/src/rustdoc/markdown_index_pass.rs b/src/rustdoc/markdown_index_pass.rs
index 9a58d0c9179..47b1cee019c 100644
--- a/src/rustdoc/markdown_index_pass.rs
+++ b/src/rustdoc/markdown_index_pass.rs
@@ -81,7 +81,7 @@ fn item_to_entry(
     let link = match doc {
       doc::modtag(_) | doc::nmodtag(_)
       if config.output_style == config::doc_per_mod => {
-        markdown_writer::make_filename(config, doc::itempage(doc))
+        markdown_writer::make_filename(config, doc::itempage(doc)).to_str()
       }
       _ => {
         ~"#" + pandoc_header_id(markdown_pass::header_text(doc))
@@ -230,7 +230,7 @@ mod test {
         do astsrv::from_str(source) |srv| {
             let config = {
                 output_style: output_style
-                with config::default_config(~"whatever")
+                with config::default_config(&Path("whatever"))
             };
             let doc = extract::from_srv(srv, ~"");
             let doc = attr_pass::mk_pass().f(srv, doc);
diff --git a/src/rustdoc/markdown_pass.rs b/src/rustdoc/markdown_pass.rs
index 6ed6dc4abab..da05b935cef 100644
--- a/src/rustdoc/markdown_pass.rs
+++ b/src/rustdoc/markdown_pass.rs
@@ -785,7 +785,7 @@ mod test {
 
             let config = {
                 output_style: config::doc_per_crate
-                with config::default_config(~"whatever")
+                with config::default_config(&Path("whatever"))
             };
 
             let doc = extract::from_srv(srv, ~"");
diff --git a/src/rustdoc/markdown_writer.rs b/src/rustdoc/markdown_writer.rs
index 74932ca579d..a62f275acc8 100644
--- a/src/rustdoc/markdown_writer.rs
+++ b/src/rustdoc/markdown_writer.rs
@@ -66,7 +66,7 @@ fn markdown_writer(
 ) -> writer {
     let filename = make_local_filename(config, page);
     do generic_writer |markdown| {
-        write_file(filename, markdown);
+        write_file(&filename, markdown);
     }
 }
 
@@ -84,7 +84,7 @@ fn pandoc_writer(
         ~"--from=markdown",
         ~"--to=html",
         ~"--css=rust.css",
-        ~"--output=" + filename
+        ~"--output=" + filename.to_str()
     ];
 
     do generic_writer |markdown| {
@@ -166,15 +166,15 @@ fn generic_writer(+process: fn~(markdown: ~str)) -> writer {
 fn make_local_filename(
     config: config::config,
     page: doc::page
-) -> ~str {
+) -> Path {
     let filename = make_filename(config, page);
-    path::connect(config.output_dir, filename)
+    config.output_dir.push_rel(&filename)
 }
 
 fn make_filename(
     config: config::config,
     page: doc::page
-) -> ~str {
+) -> Path {
     let filename = {
         match page {
           doc::cratepage(doc) => {
@@ -196,50 +196,50 @@ fn make_filename(
       config::pandoc_html => ~"html"
     };
 
-    filename + ~"." + ext
+    Path(filename).with_filetype(ext)
 }
 
 #[test]
 fn should_use_markdown_file_name_based_off_crate() {
     let config = {
-        output_dir: ~"output/dir",
+        output_dir: Path("output/dir"),
         output_format: config::markdown,
         output_style: config::doc_per_crate
-        with config::default_config(~"input/test.rc")
+        with config::default_config(&Path("input/test.rc"))
     };
     let doc = test::mk_doc(~"test", ~"");
     let page = doc::cratepage(doc.cratedoc());
     let filename = make_local_filename(config, page);
-    assert filename == ~"output/dir/test.md";
+    assert filename.to_str() == ~"output/dir/test.md";
 }
 
 #[test]
 fn should_name_html_crate_file_name_index_html_when_doc_per_mod() {
     let config = {
-        output_dir: ~"output/dir",
+        output_dir: Path("output/dir"),
         output_format: config::pandoc_html,
         output_style: config::doc_per_mod
-        with config::default_config(~"input/test.rc")
+        with config::default_config(&Path("input/test.rc"))
     };
     let doc = test::mk_doc(~"", ~"");
     let page = doc::cratepage(doc.cratedoc());
     let filename = make_local_filename(config, page);
-    assert filename == ~"output/dir/index.html";
+    assert filename.to_str() == ~"output/dir/index.html";
 }
 
 #[test]
 fn should_name_mod_file_names_by_path() {
     let config = {
-        output_dir: ~"output/dir",
+        output_dir: Path("output/dir"),
         output_format: config::pandoc_html,
         output_style: config::doc_per_mod
-        with config::default_config(~"input/test.rc")
+        with config::default_config(&Path("input/test.rc"))
     };
     let doc = test::mk_doc(~"", ~"mod a { mod b { } }");
     let modb = doc.cratemod().mods()[0].mods()[0];
     let page = doc::itempage(doc::modtag(modb));
     let filename = make_local_filename(config, page);
-    assert  filename == ~"output/dir/a_b.html";
+    assert  filename == Path("output/dir/a_b.html");
 }
 
 #[cfg(test)]
@@ -253,7 +253,7 @@ mod test {
     }
 }
 
-fn write_file(path: ~str, s: ~str) {
+fn write_file(path: &Path, s: ~str) {
     import io::WriterUtil;
 
     match io::file_writer(path, ~[io::Create, io::Truncate]) {
diff --git a/src/rustdoc/parse.rs b/src/rustdoc/parse.rs
index ca30e8aa8a8..e74700b7b67 100644
--- a/src/rustdoc/parse.rs
+++ b/src/rustdoc/parse.rs
@@ -10,7 +10,7 @@ import syntax::parse;
 
 export from_file, from_str, from_file_sess, from_str_sess;
 
-fn from_file(file: ~str) -> @ast::crate {
+fn from_file(file: &Path) -> @ast::crate {
     parse::parse_crate_from_file(
         file, ~[], parse::new_parse_sess(none))
 }
@@ -20,9 +20,9 @@ fn from_str(source: ~str) -> @ast::crate {
         ~"-", @source, ~[], parse::new_parse_sess(none))
 }
 
-fn from_file_sess(sess: session::session, file: ~str) -> @ast::crate {
+fn from_file_sess(sess: session::session, file: &Path) -> @ast::crate {
     parse::parse_crate_from_file(
-        file, cfg(sess, file_input(file)), sess.parse_sess)
+        file, cfg(sess, file_input(*file)), sess.parse_sess)
 }
 
 fn from_str_sess(sess: session::session, source: ~str) -> @ast::crate {
diff --git a/src/rustdoc/rustdoc.rs b/src/rustdoc/rustdoc.rs
index 751e94e8649..ec7556afa0a 100755
--- a/src/rustdoc/rustdoc.rs
+++ b/src/rustdoc/rustdoc.rs
@@ -130,13 +130,13 @@ fn time<T>(what: ~str, f: fn() -> T) -> T {
 fn run(config: config::config) {
 
     let source_file = config.input_crate;
-    do astsrv::from_file(source_file) |srv| {
+    do astsrv::from_file(source_file.to_str()) |srv| {
         do time(~"wait_ast") {
             do astsrv::exec(srv) |_ctxt| { }
         };
         let doc = time(~"extract", || {
             let default_name = source_file;
-            extract::from_srv(srv, default_name)
+            extract::from_srv(srv, default_name.to_str())
         });
         run_passes(srv, doc, ~[
             tystr_pass::mk_pass(),
diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs
index b912b2cb12d..21525424b1b 100644
--- a/src/test/bench/core-std.rs
+++ b/src/test/bench/core-std.rs
@@ -52,13 +52,11 @@ fn shift_push() {
 }
 
 fn read_line() {
-    let path = path::connect(
-        env!("CFG_SRC_DIR"),
-        ~"src/test/bench/shootout-k-nucleotide.data"
-    );
+    let path = Path(env!("CFG_SRC_DIR"))
+        .push_rel(&Path("src/test/bench/shootout-k-nucleotide.data"));
 
     for int::range(0, 3) |_i| {
-        let reader = result::get(io::file_reader(path));
+        let reader = result::get(io::file_reader(&path));
         while !reader.eof() {
             reader.read_line();
         }
diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs
index 4b83b14c98f..b9dc89c43c5 100644
--- a/src/test/bench/shootout-fasta.rs
+++ b/src/test/bench/shootout-fasta.rs
@@ -85,7 +85,8 @@ fn main(args: ~[~str]) {
     };
 
     let writer = if os::getenv(~"RUST_BENCH").is_some() {
-        result::get(io::file_writer(~"./shootout-fasta.data", ~[io::Truncate, io::Create]))
+        result::get(io::file_writer(&Path("./shootout-fasta.data"),
+                                    ~[io::Truncate, io::Create]))
     } else {
         io::stdout()
     };
diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs
index 75a4c4f7ea4..4204a3110de 100644
--- a/src/test/bench/shootout-k-nucleotide-pipes.rs
+++ b/src/test/bench/shootout-k-nucleotide-pipes.rs
@@ -128,11 +128,9 @@ fn main(args: ~[~str]) {
    let rdr = if os::getenv(~"RUST_BENCH").is_some() {
        // FIXME: Using this compile-time env variable is a crummy way to
        // get to this massive data set, but #include_bin chokes on it (#2598)
-       let path = path::connect(
-           env!("CFG_SRC_DIR"),
-           ~"src/test/bench/shootout-k-nucleotide.data"
-           );
-       result::get(io::file_reader(path))
+       let path = Path(env!("CFG_SRC_DIR"))
+           .push_rel(&Path("src/test/bench/shootout-k-nucleotide.data"));
+       result::get(io::file_reader(&path))
    } else {
       io::stdin()
    };
diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs
index 5e7b705714d..54ff0cde9ef 100644
--- a/src/test/bench/shootout-k-nucleotide.rs
+++ b/src/test/bench/shootout-k-nucleotide.rs
@@ -126,11 +126,9 @@ fn main(args: ~[~str]) {
    let rdr = if os::getenv(~"RUST_BENCH").is_some() {
        // FIXME: Using this compile-time env variable is a crummy way to
        // get to this massive data set, but #include_bin chokes on it (#2598)
-       let path = path::connect(
-           env!("CFG_SRC_DIR"),
-           ~"src/test/bench/shootout-k-nucleotide.data"
-           );
-       result::get(io::file_reader(path))
+       let path = Path(env!("CFG_SRC_DIR"))
+           .push_rel(&Path("src/test/bench/shootout-k-nucleotide.data"));
+       result::get(io::file_reader(&path))
    } else {
       io::stdin()
    };
diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs
index 1f380d79269..1d1c2e2ac29 100644
--- a/src/test/bench/shootout-mandelbrot.rs
+++ b/src/test/bench/shootout-mandelbrot.rs
@@ -112,7 +112,7 @@ fn writer(path: ~str, writech: comm::Chan<comm::Chan<line>>, size: uint)
         }
         _ => {
             result::get(
-                io::file_writer(path,
+                io::file_writer(&Path(path),
                 ~[io::Create, io::Truncate]))
         }
     };
diff --git a/src/test/bench/task-perf-word-count-generic.rs b/src/test/bench/task-perf-word-count-generic.rs
index 06ecec92d8d..3ab3a08c8a4 100644
--- a/src/test/bench/task-perf-word-count-generic.rs
+++ b/src/test/bench/task-perf-word-count-generic.rs
@@ -80,7 +80,7 @@ impl io::Reader: word_reader {
 }
 
 fn file_word_reader(filename: ~str) -> word_reader {
-    match io::file_reader(filename) {
+    match io::file_reader(&Path(filename)) {
       result::ok(f) => { f as word_reader }
       result::err(e) => { fail fmt!("%?", e) }
     }