From c27a82f19352f37a6b04d7733d28c84494c3afd4 Mon Sep 17 00:00:00 2001
From: Philip Craig <philipjcraig@gmail.com>
Date: Sat, 30 Sep 2017 16:28:48 +1000
Subject: [PATCH 1/3] Don't use remapped path when loading modules and include
 files

---
 src/librustc/ich/impls_syntax.rs              |  1 +
 src/librustc/session/mod.rs                   |  4 +---
 src/libsyntax/codemap.rs                      | 16 ++++++++++++++--
 src/libsyntax/ext/expand.rs                   |  6 ++----
 src/libsyntax/ext/source_util.rs              |  2 +-
 src/libsyntax/parse/parser.rs                 |  2 +-
 src/libsyntax_pos/lib.rs                      |  6 ++++++
 src/test/codegen/remap_path_prefix/aux_mod.rs | 16 ++++++++++++++++
 src/test/codegen/remap_path_prefix/main.rs    |  7 +++++++
 9 files changed, 49 insertions(+), 11 deletions(-)
 create mode 100644 src/test/codegen/remap_path_prefix/aux_mod.rs

diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 669e1ba773e23..87e41d30e5dc4 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -354,6 +354,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap {
         let FileMap {
             ref name,
             name_was_remapped,
+            path: _,
             crate_of_origin,
             // Do not hash the source as it is not encoded
             src: _,
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index e87443619ece7..bd6e5eb67c87c 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -68,8 +68,7 @@ pub struct Session {
     pub derive_registrar_fn: Cell<Option<ast::NodeId>>,
     pub default_sysroot: Option<PathBuf>,
     // The name of the root source file of the crate, in the local file system.
-    // The path is always expected to be absolute. `None` means that there is no
-    // source file.
+    // `None` means that there is no source file.
     pub local_crate_source_file: Option<String>,
     // The directory the compiler has been executed in plus a flag indicating
     // if the value stored here has been affected by path remapping.
@@ -722,7 +721,6 @@ pub fn build_session_(sopts: config::Options,
 
     let file_path_mapping = sopts.file_path_mapping();
 
-    // Make the path absolute, if necessary
     let local_crate_source_file = local_crate_source_file.map(|path| {
         file_path_mapping.map_prefix(path.to_string_lossy().into_owned()).0
     });
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index cd4a6f921fe6f..792625808587d 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -162,9 +162,16 @@ impl CodeMap {
         let start_pos = self.next_start_pos();
         let mut files = self.files.borrow_mut();
 
+        // The path is used to determine the directory for loading submodules and
+        // include files, so it must be before remapping.
+        // Note that filename may not be a valid path, eg it may be `<anon>` etc,
+        // but this is okay because the directory determined by `path.pop()` will
+        // be empty, so the working directory will be used.
+        let path = PathBuf::from(filename.clone());
+
         let (filename, was_remapped) = self.path_mapping.map_prefix(filename);
         let filemap =
-            Rc::new(FileMap::new(filename, was_remapped, src, Pos::from_usize(start_pos)));
+            Rc::new(FileMap::new(filename, was_remapped, path, src, Pos::from_usize(start_pos)));
 
         files.push(filemap.clone());
 
@@ -216,6 +223,7 @@ impl CodeMap {
         let filemap = Rc::new(FileMap {
             name: filename,
             name_was_remapped,
+            path: PathBuf::new(),
             crate_of_origin,
             src: None,
             src_hash,
@@ -342,7 +350,11 @@ impl CodeMap {
     }
 
     pub fn span_to_filename(&self, sp: Span) -> FileName {
-        self.lookup_char_pos(sp.lo()).file.name.to_string()
+        self.lookup_char_pos(sp.lo()).file.name.clone()
+    }
+
+    pub fn span_to_path(&self, sp: Span) -> PathBuf {
+        self.lookup_char_pos(sp.lo()).file.path.clone()
     }
 
     pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6e7a8203b61ca..c4727b6eda50f 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -35,7 +35,6 @@ use visit::Visitor;
 
 use std::collections::HashMap;
 use std::mem;
-use std::path::PathBuf;
 use std::rc::Rc;
 
 macro_rules! expansions {
@@ -200,7 +199,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         self.cx.crate_root = std_inject::injected_crate_name(&krate);
         let mut module = ModuleData {
             mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
-            directory: PathBuf::from(self.cx.codemap().span_to_filename(krate.span)),
+            directory: self.cx.codemap().span_to_path(krate.span),
         };
         module.directory.pop();
         self.cx.current_expansion.module = Rc::new(module);
@@ -952,8 +951,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                         module.directory.push(&*item.ident.name.as_str());
                     }
                 } else {
-                    let mut path =
-                        PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
+                    let mut path = self.cx.parse_sess.codemap().span_to_path(inner);
                     let directory_ownership = match path.file_name().unwrap().to_str() {
                         Some("mod.rs") => DirectoryOwnership::Owned,
                         _ => DirectoryOwnership::UnownedViaMod(false),
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 18a262d139a27..8bc7f05567681 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -197,7 +197,7 @@ fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf {
     // after macro expansion (that is, they are unhygienic).
     if !arg.is_absolute() {
         let callsite = sp.source_callsite();
-        let mut path = PathBuf::from(&cx.codemap().span_to_filename(callsite));
+        let mut path = cx.codemap().span_to_path(callsite);
         path.pop();
         path.push(arg);
         path
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d5ba4b54d9014..bd1d4241be05e 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -525,7 +525,7 @@ impl<'a> Parser<'a> {
         if let Some(directory) = directory {
             parser.directory = directory;
         } else if parser.span != syntax_pos::DUMMY_SP {
-            parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span));
+            parser.directory.path = sess.codemap().span_to_path(parser.span);
             parser.directory.path.pop();
         }
 
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 582f279818134..0d910cc04f6cc 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -32,6 +32,7 @@ use std::cmp::{self, Ordering};
 use std::fmt;
 use std::hash::Hasher;
 use std::ops::{Add, Sub};
+use std::path::PathBuf;
 use std::rc::Rc;
 
 use rustc_data_structures::stable_hasher::StableHasher;
@@ -501,6 +502,8 @@ pub struct FileMap {
     pub name: FileName,
     /// True if the `name` field above has been modified by -Zremap-path-prefix
     pub name_was_remapped: bool,
+    /// The path of the file that the source came from.
+    pub path: PathBuf,
     /// Indicates which crate this FileMap was imported from.
     pub crate_of_origin: u32,
     /// The complete source code
@@ -626,6 +629,7 @@ impl Decodable for FileMap {
             Ok(FileMap {
                 name,
                 name_was_remapped,
+                path: PathBuf::new(),
                 // `crate_of_origin` has to be set by the importer.
                 // This value matches up with rustc::hir::def_id::INVALID_CRATE.
                 // That constant is not available here unfortunately :(
@@ -651,6 +655,7 @@ impl fmt::Debug for FileMap {
 impl FileMap {
     pub fn new(name: FileName,
                name_was_remapped: bool,
+               path: PathBuf,
                mut src: String,
                start_pos: BytePos) -> FileMap {
         remove_bom(&mut src);
@@ -664,6 +669,7 @@ impl FileMap {
         FileMap {
             name,
             name_was_remapped,
+            path,
             crate_of_origin: 0,
             src: Some(Rc::new(src)),
             src_hash,
diff --git a/src/test/codegen/remap_path_prefix/aux_mod.rs b/src/test/codegen/remap_path_prefix/aux_mod.rs
new file mode 100644
index 0000000000000..2a7019957af15
--- /dev/null
+++ b/src/test/codegen/remap_path_prefix/aux_mod.rs
@@ -0,0 +1,16 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test: this is not a test
+
+#[inline]
+pub fn some_aux_mod_function() -> i32 {
+    1234
+}
diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs
index eb00c91ba5f39..c73739bb76543 100644
--- a/src/test/codegen/remap_path_prefix/main.rs
+++ b/src/test/codegen/remap_path_prefix/main.rs
@@ -16,12 +16,19 @@
 
 extern crate remap_path_prefix_aux;
 
+// Here we check that submodules and include files are found using the path without
+// remapping. This test requires that rustc is called with an absolute path.
+mod aux_mod;
+include!("aux_mod.rs");
+
 // Here we check that the expansion of the file!() macro is mapped.
 // CHECK: internal constant [34 x i8] c"/the/src/remap_path_prefix/main.rs"
 pub static FILE_PATH: &'static str = file!();
 
 fn main() {
     remap_path_prefix_aux::some_aux_function();
+    aux_mod::some_aux_mod_function();
+    some_aux_mod_function();
 }
 
 // Here we check that local debuginfo is mapped correctly.

From 3a225c77bba8576333924e7435493cb4d4e0cbaf Mon Sep 17 00:00:00 2001
From: Philip Craig <philipjcraig@gmail.com>
Date: Tue, 3 Oct 2017 19:44:58 +1000
Subject: [PATCH 2/3] Rename FileMap::path and change to an Option

---
 src/librustc/ich/impls_syntax.rs |  2 +-
 src/libsyntax/codemap.rs         | 18 ++++++++++++------
 src/libsyntax/ext/expand.rs      |  4 ++--
 src/libsyntax/ext/source_util.rs |  2 +-
 src/libsyntax/parse/parser.rs    |  2 +-
 src/libsyntax_pos/lib.rs         | 11 ++++++-----
 6 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 87e41d30e5dc4..799e790b85fb5 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -354,7 +354,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap {
         let FileMap {
             ref name,
             name_was_remapped,
-            path: _,
+            unmapped_path: _,
             crate_of_origin,
             // Do not hash the source as it is not encoded
             src: _,
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 792625808587d..efaa5e5e3dab2 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -167,11 +167,16 @@ impl CodeMap {
         // Note that filename may not be a valid path, eg it may be `<anon>` etc,
         // but this is okay because the directory determined by `path.pop()` will
         // be empty, so the working directory will be used.
-        let path = PathBuf::from(filename.clone());
+        let unmapped_path = PathBuf::from(filename.clone());
 
         let (filename, was_remapped) = self.path_mapping.map_prefix(filename);
-        let filemap =
-            Rc::new(FileMap::new(filename, was_remapped, path, src, Pos::from_usize(start_pos)));
+        let filemap = Rc::new(FileMap::new(
+            filename,
+            was_remapped,
+            unmapped_path,
+            src,
+            Pos::from_usize(start_pos),
+        ));
 
         files.push(filemap.clone());
 
@@ -223,7 +228,7 @@ impl CodeMap {
         let filemap = Rc::new(FileMap {
             name: filename,
             name_was_remapped,
-            path: PathBuf::new(),
+            unmapped_path: None,
             crate_of_origin,
             src: None,
             src_hash,
@@ -353,8 +358,9 @@ impl CodeMap {
         self.lookup_char_pos(sp.lo()).file.name.clone()
     }
 
-    pub fn span_to_path(&self, sp: Span) -> PathBuf {
-        self.lookup_char_pos(sp.lo()).file.path.clone()
+    pub fn span_to_unmapped_path(&self, sp: Span) -> PathBuf {
+        self.lookup_char_pos(sp.lo()).file.unmapped_path.clone()
+            .expect("CodeMap::span_to_unmapped_path called for imported FileMap?")
     }
 
     pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index c4727b6eda50f..614c4a10e6d80 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -199,7 +199,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         self.cx.crate_root = std_inject::injected_crate_name(&krate);
         let mut module = ModuleData {
             mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
-            directory: self.cx.codemap().span_to_path(krate.span),
+            directory: self.cx.codemap().span_to_unmapped_path(krate.span),
         };
         module.directory.pop();
         self.cx.current_expansion.module = Rc::new(module);
@@ -951,7 +951,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                         module.directory.push(&*item.ident.name.as_str());
                     }
                 } else {
-                    let mut path = self.cx.parse_sess.codemap().span_to_path(inner);
+                    let mut path = self.cx.parse_sess.codemap().span_to_unmapped_path(inner);
                     let directory_ownership = match path.file_name().unwrap().to_str() {
                         Some("mod.rs") => DirectoryOwnership::Owned,
                         _ => DirectoryOwnership::UnownedViaMod(false),
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 8bc7f05567681..86657e675b2de 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -197,7 +197,7 @@ fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf {
     // after macro expansion (that is, they are unhygienic).
     if !arg.is_absolute() {
         let callsite = sp.source_callsite();
-        let mut path = cx.codemap().span_to_path(callsite);
+        let mut path = cx.codemap().span_to_unmapped_path(callsite);
         path.pop();
         path.push(arg);
         path
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index bd1d4241be05e..65dabe98a063c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -525,7 +525,7 @@ impl<'a> Parser<'a> {
         if let Some(directory) = directory {
             parser.directory = directory;
         } else if parser.span != syntax_pos::DUMMY_SP {
-            parser.directory.path = sess.codemap().span_to_path(parser.span);
+            parser.directory.path = sess.codemap().span_to_unmapped_path(parser.span);
             parser.directory.path.pop();
         }
 
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 0d910cc04f6cc..2000db9703cf9 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -502,8 +502,9 @@ pub struct FileMap {
     pub name: FileName,
     /// True if the `name` field above has been modified by -Zremap-path-prefix
     pub name_was_remapped: bool,
-    /// The path of the file that the source came from.
-    pub path: PathBuf,
+    /// The unmapped path of the file that the source came from.
+    /// Set to `None` if the FileMap was imported from an external crate.
+    pub unmapped_path: Option<PathBuf>,
     /// Indicates which crate this FileMap was imported from.
     pub crate_of_origin: u32,
     /// The complete source code
@@ -629,7 +630,7 @@ impl Decodable for FileMap {
             Ok(FileMap {
                 name,
                 name_was_remapped,
-                path: PathBuf::new(),
+                unmapped_path: None,
                 // `crate_of_origin` has to be set by the importer.
                 // This value matches up with rustc::hir::def_id::INVALID_CRATE.
                 // That constant is not available here unfortunately :(
@@ -655,7 +656,7 @@ impl fmt::Debug for FileMap {
 impl FileMap {
     pub fn new(name: FileName,
                name_was_remapped: bool,
-               path: PathBuf,
+               unmapped_path: PathBuf,
                mut src: String,
                start_pos: BytePos) -> FileMap {
         remove_bom(&mut src);
@@ -669,7 +670,7 @@ impl FileMap {
         FileMap {
             name,
             name_was_remapped,
-            path,
+            unmapped_path: Some(unmapped_path),
             crate_of_origin: 0,
             src: Some(Rc::new(src)),
             src_hash,

From 9bbd7a3b3f2f713220f429bd15466135efa7f3b7 Mon Sep 17 00:00:00 2001
From: Philip Craig <philipjcraig@gmail.com>
Date: Tue, 3 Oct 2017 20:35:55 +1000
Subject: [PATCH 3/3] Add fixme regarding remapping paths for doctests

---
 src/librustdoc/test.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 7fa1b38bdadfa..5ce73d38fdf0e 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -184,6 +184,8 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec<String>, libs
     // the test harness wants its own `main` & top level functions, so
     // never wrap the test in `fn main() { ... }`
     let test = make_test(test, Some(cratename), as_test_harness, opts);
+    // FIXME(#44940): if doctests ever support path remapping, then this filename
+    // needs to be the result of CodeMap::span_to_unmapped_path
     let input = config::Input::Str {
         name: filename.to_owned(),
         input: test.to_owned(),