From ba78db310b2ddf9b5f8e6c87a58e8ea8df374e16 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Tue, 14 May 2019 21:50:39 +0200
Subject: [PATCH 1/7] libsyntax: factor out file path resolving

This allows the same logic used by `include_X!` macros to be used by
`#[doc(include)]`.
---
 src/libsyntax/ext/source_util.rs | 33 ++++++--------------------------
 src/libsyntax/lib.rs             |  1 +
 src/libsyntax/util/path.rs       | 28 +++++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 27 deletions(-)
 create mode 100644 src/libsyntax/util/path.rs

diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index c2ba8b983f5a8..aad390f3bf601 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -6,13 +6,13 @@ use crate::print::pprust;
 use crate::ptr::P;
 use crate::symbol::Symbol;
 use crate::tokenstream;
+use crate::util::path;
 
 use smallvec::SmallVec;
-use syntax_pos::{self, Pos, Span, FileName};
+use syntax_pos::{self, Pos, Span};
 
 use std::fs;
 use std::io::ErrorKind;
-use std::path::PathBuf;
 use rustc_data_structures::sync::Lrc;
 
 // These macros all relate to the file system; they either return
@@ -78,9 +78,9 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea
         None => return DummyResult::any(sp),
     };
     // The file will be added to the code map by the parser
-    let path = res_rel_file(cx, sp, file);
+    let file = path::resolve(file, sp, cx.source_map());
     let directory_ownership = DirectoryOwnership::Owned { relative: None };
-    let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, directory_ownership, None, sp);
+    let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp);
 
     struct ExpandResult<'a> {
         p: parse::parser::Parser<'a>,
@@ -115,7 +115,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To
         Some(f) => f,
         None => return DummyResult::expr(sp)
     };
-    let file = res_rel_file(cx, sp, file);
+    let file = path::resolve(file, sp, cx.source_map());
     match fs::read_to_string(&file) {
         Ok(src) => {
             let interned_src = Symbol::intern(&src);
@@ -143,7 +143,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::
         Some(f) => f,
         None => return DummyResult::expr(sp)
     };
-    let file = res_rel_file(cx, sp, file);
+    let file = path::resolve(file, sp, cx.source_map());
     match fs::read(&file) {
         Ok(bytes) => {
             // Add the contents to the source map if it contains UTF-8.
@@ -164,24 +164,3 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::
         }
     }
 }
-
-// resolve a file-system path to an absolute file-system path (if it
-// isn't already)
-fn res_rel_file(cx: &mut ExtCtxt<'_>, sp: syntax_pos::Span, arg: String) -> PathBuf {
-    let arg = PathBuf::from(arg);
-    // Relative paths are resolved relative to the file in which they are found
-    // after macro expansion (that is, they are unhygienic).
-    if !arg.is_absolute() {
-        let callsite = sp.source_callsite();
-        let mut path = match cx.source_map().span_to_unmapped_path(callsite) {
-            FileName::Real(path) => path,
-            FileName::DocTest(path, _) => path,
-            other => panic!("cannot resolve relative path in non-file source `{}`", other),
-        };
-        path.pop();
-        path.push(arg);
-        path
-    } else {
-        arg
-    }
-}
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 3dea1977c4dac..1b2873b1de7bc 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -135,6 +135,7 @@ pub mod util {
     #[cfg(test)]
     pub mod parser_testing;
     pub mod map_in_place;
+    pub mod path;
 }
 
 pub mod json;
diff --git a/src/libsyntax/util/path.rs b/src/libsyntax/util/path.rs
new file mode 100644
index 0000000000000..a3511bac8e7d9
--- /dev/null
+++ b/src/libsyntax/util/path.rs
@@ -0,0 +1,28 @@
+use crate::source_map::SourceMap;
+use std::path::PathBuf;
+use syntax_pos::{Span, FileName};
+
+/// Resolve a path mentioned inside Rust code.
+///
+/// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
+///
+/// Returns an absolute path to the file that `path` refers to.
+pub fn resolve(path: impl Into<PathBuf>, span: Span, map: &SourceMap) -> PathBuf {
+    let path = path.into();
+
+    // Relative paths are resolved relative to the file in which they are found
+    // after macro expansion (that is, they are unhygienic).
+    if !path.is_absolute() {
+        let callsite = span.source_callsite();
+        let mut result = match map.span_to_unmapped_path(callsite) {
+            FileName::Real(path) => path,
+            FileName::DocTest(path, _) => path,
+            other => panic!("cannot resolve relative path in non-file source `{}`", other),
+        };
+        result.pop();
+        result.push(path);
+        result
+    } else {
+        path
+    }
+}

From 138e08ccf6f6c6caf55a135bd0edcba8e6855df5 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sat, 18 May 2019 15:56:53 +0200
Subject: [PATCH 2/7] Make #[doc(include)] paths behave like other paths

This makes them relative to the containing file instead of the crate
root
---
 src/libstd/os/raw/mod.rs    | 48 ++++++++++++++++++++++++-------------
 src/libsyntax/ext/expand.rs |  7 ++----
 2 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs
index c0b0b6d40d891..fd50657800d50 100644
--- a/src/libstd/os/raw/mod.rs
+++ b/src/libstd/os/raw/mod.rs
@@ -8,7 +8,8 @@
 
 #![stable(feature = "raw_os", since = "1.1.0")]
 
-#[doc(include = "os/raw/char.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/char.md"))]
+#[cfg_attr(not(stage0), doc(include = "char.md"))]
 #[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
                                        target_arch = "arm",
                                        target_arch = "powerpc",
@@ -31,7 +32,8 @@
                                          target_arch = "powerpc")),
           all(target_os = "fuchsia", target_arch = "aarch64")))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
-#[doc(include = "os/raw/char.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/char.md"))]
+#[cfg_attr(not(stage0), doc(include = "char.md"))]
 #[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
                                            target_arch = "arm",
                                            target_arch = "powerpc",
@@ -54,37 +56,51 @@
                                              target_arch = "powerpc")),
               all(target_os = "fuchsia", target_arch = "aarch64"))))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
-#[doc(include = "os/raw/schar.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/schar.md"))]
+#[cfg_attr(not(stage0), doc(include = "schar.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
-#[doc(include = "os/raw/uchar.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/uchar.md"))]
+#[cfg_attr(not(stage0), doc(include = "uchar.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
-#[doc(include = "os/raw/short.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/short.md"))]
+#[cfg_attr(not(stage0), doc(include = "short.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
-#[doc(include = "os/raw/ushort.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/ushort.md"))]
+#[cfg_attr(not(stage0), doc(include = "ushort.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
-#[doc(include = "os/raw/int.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/int.md"))]
+#[cfg_attr(not(stage0), doc(include = "int.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
-#[doc(include = "os/raw/uint.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/uint.md"))]
+#[cfg_attr(not(stage0), doc(include = "uint.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
-#[doc(include = "os/raw/long.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/long.md"))]
+#[cfg_attr(not(stage0), doc(include = "long.md"))]
 #[cfg(any(target_pointer_width = "32", windows))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
-#[doc(include = "os/raw/ulong.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/ulong.md"))]
+#[cfg_attr(not(stage0), doc(include = "ulong.md"))]
 #[cfg(any(target_pointer_width = "32", windows))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
-#[doc(include = "os/raw/long.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/long.md"))]
+#[cfg_attr(not(stage0), doc(include = "long.md"))]
 #[cfg(all(target_pointer_width = "64", not(windows)))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
-#[doc(include = "os/raw/ulong.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/ulong.md"))]
+#[cfg_attr(not(stage0), doc(include = "ulong.md"))]
 #[cfg(all(target_pointer_width = "64", not(windows)))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
-#[doc(include = "os/raw/longlong.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/longlong.md"))]
+#[cfg_attr(not(stage0), doc(include = "longlong.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
-#[doc(include = "os/raw/ulonglong.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/ulonglong.md"))]
+#[cfg_attr(not(stage0), doc(include = "ulonglong.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
-#[doc(include = "os/raw/float.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/float.md"))]
+#[cfg_attr(not(stage0), doc(include = "float.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
-#[doc(include = "os/raw/double.md")]
+#[cfg_attr(stage0, doc(include = "os/raw/double.md"))]
+#[cfg_attr(not(stage0), doc(include = "double.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
 
 #[stable(feature = "raw_os", since = "1.1.0")]
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index ae72f1fd108ed..6cfcfdfbf7d85 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -17,6 +17,7 @@ use crate::symbol::{sym, Symbol};
 use crate::tokenstream::{TokenStream, TokenTree};
 use crate::visit::{self, Visitor};
 use crate::util::map_in_place::MapInPlace;
+use crate::util::path;
 
 use errors::{Applicability, FatalError};
 use smallvec::{smallvec, SmallVec};
@@ -1253,7 +1254,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                         return noop_visit_attribute(at, self);
                     }
 
-                    let filename = self.cx.root_path.join(file.to_string());
+                    let filename = path::resolve(&*file.as_str(), it.span(), self.cx.source_map());
                     match fs::read_to_string(&filename) {
                         Ok(src) => {
                             let src_interned = Symbol::intern(&src);
@@ -1302,10 +1303,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                                 );
                                 err.span_label(lit.span, "couldn't read file");
 
-                                if e.kind() == ErrorKind::NotFound {
-                                    err.help("external doc paths are relative to the crate root");
-                                }
-
                                 err.emit();
                             }
                         }

From 1cc7c211f5ff566f0ea2270197a15d1ab8c429bf Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sun, 19 May 2019 13:33:16 +0200
Subject: [PATCH 3/7] Adjust docs to new #[doc(include)] behaviour

---
 src/doc/rustdoc/src/unstable-features.md | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 1d9510c9aacab..6e32468b64dee 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -183,9 +183,8 @@ Book][unstable-masked] and [its tracking issue][issue-masked].
 
 As designed in [RFC 1990], Rustdoc can read an external file to use as a type's documentation. This
 is useful if certain documentation is so long that it would break the flow of reading the source.
-Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` (where `sometype.md` is
-a file adjacent to the `lib.rs` for the crate) will ask Rustdoc to instead read that file and use it
-as if it were written inline.
+Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` will ask Rustdoc to
+instead read that file and use it as if it were written inline.
 
 [RFC 1990]: https://github.com/rust-lang/rfcs/pull/1990
 

From 8ccf52c1c6cffde2905d7ad0ebfa36a9e8a0c319 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sat, 22 Jun 2019 20:37:25 +0200
Subject: [PATCH 4/7] stage0 -> bootstrap

---
 src/libstd/os/raw/mod.rs | 64 ++++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs
index fd50657800d50..340b2a5d5519e 100644
--- a/src/libstd/os/raw/mod.rs
+++ b/src/libstd/os/raw/mod.rs
@@ -8,8 +8,8 @@
 
 #![stable(feature = "raw_os", since = "1.1.0")]
 
-#[cfg_attr(stage0, doc(include = "os/raw/char.md"))]
-#[cfg_attr(not(stage0), doc(include = "char.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/char.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "char.md"))]
 #[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
                                        target_arch = "arm",
                                        target_arch = "powerpc",
@@ -32,8 +32,8 @@
                                          target_arch = "powerpc")),
           all(target_os = "fuchsia", target_arch = "aarch64")))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
-#[cfg_attr(stage0, doc(include = "os/raw/char.md"))]
-#[cfg_attr(not(stage0), doc(include = "char.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/char.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "char.md"))]
 #[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
                                            target_arch = "arm",
                                            target_arch = "powerpc",
@@ -56,51 +56,51 @@
                                              target_arch = "powerpc")),
               all(target_os = "fuchsia", target_arch = "aarch64"))))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
-#[cfg_attr(stage0, doc(include = "os/raw/schar.md"))]
-#[cfg_attr(not(stage0), doc(include = "schar.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/schar.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "schar.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
-#[cfg_attr(stage0, doc(include = "os/raw/uchar.md"))]
-#[cfg_attr(not(stage0), doc(include = "uchar.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/uchar.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "uchar.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
-#[cfg_attr(stage0, doc(include = "os/raw/short.md"))]
-#[cfg_attr(not(stage0), doc(include = "short.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/short.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "short.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
-#[cfg_attr(stage0, doc(include = "os/raw/ushort.md"))]
-#[cfg_attr(not(stage0), doc(include = "ushort.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/ushort.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "ushort.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
-#[cfg_attr(stage0, doc(include = "os/raw/int.md"))]
-#[cfg_attr(not(stage0), doc(include = "int.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/int.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "int.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
-#[cfg_attr(stage0, doc(include = "os/raw/uint.md"))]
-#[cfg_attr(not(stage0), doc(include = "uint.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/uint.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "uint.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
-#[cfg_attr(stage0, doc(include = "os/raw/long.md"))]
-#[cfg_attr(not(stage0), doc(include = "long.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/long.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "long.md"))]
 #[cfg(any(target_pointer_width = "32", windows))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
-#[cfg_attr(stage0, doc(include = "os/raw/ulong.md"))]
-#[cfg_attr(not(stage0), doc(include = "ulong.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/ulong.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "ulong.md"))]
 #[cfg(any(target_pointer_width = "32", windows))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
-#[cfg_attr(stage0, doc(include = "os/raw/long.md"))]
-#[cfg_attr(not(stage0), doc(include = "long.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/long.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "long.md"))]
 #[cfg(all(target_pointer_width = "64", not(windows)))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
-#[cfg_attr(stage0, doc(include = "os/raw/ulong.md"))]
-#[cfg_attr(not(stage0), doc(include = "ulong.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/ulong.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "ulong.md"))]
 #[cfg(all(target_pointer_width = "64", not(windows)))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
-#[cfg_attr(stage0, doc(include = "os/raw/longlong.md"))]
-#[cfg_attr(not(stage0), doc(include = "longlong.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/longlong.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "longlong.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
-#[cfg_attr(stage0, doc(include = "os/raw/ulonglong.md"))]
-#[cfg_attr(not(stage0), doc(include = "ulonglong.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/ulonglong.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "ulonglong.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
-#[cfg_attr(stage0, doc(include = "os/raw/float.md"))]
-#[cfg_attr(not(stage0), doc(include = "float.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/float.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "float.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
-#[cfg_attr(stage0, doc(include = "os/raw/double.md"))]
-#[cfg_attr(not(stage0), doc(include = "double.md"))]
+#[cfg_attr(bootstrap, doc(include = "os/raw/double.md"))]
+#[cfg_attr(not(bootstrap), doc(include = "double.md"))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
 
 #[stable(feature = "raw_os", since = "1.1.0")]

From edb21873cced7a179571aa3a9c25eb1cfc05c2db Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Sat, 22 Jun 2019 21:51:51 +0200
Subject: [PATCH 5/7] Make path::resolve a method on ExtCtxt

---
 src/libsyntax/ext/base.rs        | 27 ++++++++++++++++++++++++++-
 src/libsyntax/ext/expand.rs      |  3 +--
 src/libsyntax/ext/source_util.rs |  7 +++----
 src/libsyntax/lib.rs             |  1 -
 src/libsyntax/util/path.rs       | 28 ----------------------------
 5 files changed, 30 insertions(+), 36 deletions(-)
 delete mode 100644 src/libsyntax/util/path.rs

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 926c9e88efe15..11b7a984aaa00 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -1,6 +1,6 @@
 use crate::ast::{self, Attribute, Name, PatKind};
 use crate::attr::{HasAttrs, Stability, Deprecation};
-use crate::source_map::{SourceMap, Spanned, respan};
+use crate::source_map::{SourceMap, Spanned, FileName, respan};
 use crate::edition::Edition;
 use crate::ext::expand::{self, AstFragment, Invocation};
 use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency};
@@ -889,6 +889,31 @@ impl<'a> ExtCtxt<'a> {
     pub fn check_unused_macros(&self) {
         self.resolver.check_unused_macros();
     }
+
+    /// Resolve a path mentioned inside Rust code.
+    ///
+    /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
+    ///
+    /// Returns an absolute path to the file that `path` refers to.
+    pub fn resolve_path(&self, path: impl Into<PathBuf>, span: Span) -> PathBuf {
+        let path = path.into();
+
+        // Relative paths are resolved relative to the file in which they are found
+        // after macro expansion (that is, they are unhygienic).
+        if !path.is_absolute() {
+            let callsite = span.source_callsite();
+            let mut result = match self.source_map().span_to_unmapped_path(callsite) {
+                FileName::Real(path) => path,
+                FileName::DocTest(path, _) => path,
+                other => panic!("cannot resolve relative path in non-file source `{}`", other),
+            };
+            result.pop();
+            result.push(path);
+            result
+        } else {
+            path
+        }
+    }
 }
 
 /// Extracts a string literal from the macro expanded version of `expr`,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6cfcfdfbf7d85..ae8b11ff9d50e 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -17,7 +17,6 @@ use crate::symbol::{sym, Symbol};
 use crate::tokenstream::{TokenStream, TokenTree};
 use crate::visit::{self, Visitor};
 use crate::util::map_in_place::MapInPlace;
-use crate::util::path;
 
 use errors::{Applicability, FatalError};
 use smallvec::{smallvec, SmallVec};
@@ -1254,7 +1253,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                         return noop_visit_attribute(at, self);
                     }
 
-                    let filename = path::resolve(&*file.as_str(), it.span(), self.cx.source_map());
+                    let filename = self.cx.resolve_path(&*file.as_str(), it.span());
                     match fs::read_to_string(&filename) {
                         Ok(src) => {
                             let src_interned = Symbol::intern(&src);
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index aad390f3bf601..ae080c05eec91 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -6,7 +6,6 @@ use crate::print::pprust;
 use crate::ptr::P;
 use crate::symbol::Symbol;
 use crate::tokenstream;
-use crate::util::path;
 
 use smallvec::SmallVec;
 use syntax_pos::{self, Pos, Span};
@@ -78,7 +77,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea
         None => return DummyResult::any(sp),
     };
     // The file will be added to the code map by the parser
-    let file = path::resolve(file, sp, cx.source_map());
+    let file = cx.resolve_path(file, sp);
     let directory_ownership = DirectoryOwnership::Owned { relative: None };
     let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp);
 
@@ -115,7 +114,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To
         Some(f) => f,
         None => return DummyResult::expr(sp)
     };
-    let file = path::resolve(file, sp, cx.source_map());
+    let file = cx.resolve_path(file, sp);
     match fs::read_to_string(&file) {
         Ok(src) => {
             let interned_src = Symbol::intern(&src);
@@ -143,7 +142,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::
         Some(f) => f,
         None => return DummyResult::expr(sp)
     };
-    let file = path::resolve(file, sp, cx.source_map());
+    let file = cx.resolve_path(file, sp);
     match fs::read(&file) {
         Ok(bytes) => {
             // Add the contents to the source map if it contains UTF-8.
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 1b2873b1de7bc..3dea1977c4dac 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -135,7 +135,6 @@ pub mod util {
     #[cfg(test)]
     pub mod parser_testing;
     pub mod map_in_place;
-    pub mod path;
 }
 
 pub mod json;
diff --git a/src/libsyntax/util/path.rs b/src/libsyntax/util/path.rs
deleted file mode 100644
index a3511bac8e7d9..0000000000000
--- a/src/libsyntax/util/path.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-use crate::source_map::SourceMap;
-use std::path::PathBuf;
-use syntax_pos::{Span, FileName};
-
-/// Resolve a path mentioned inside Rust code.
-///
-/// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
-///
-/// Returns an absolute path to the file that `path` refers to.
-pub fn resolve(path: impl Into<PathBuf>, span: Span, map: &SourceMap) -> PathBuf {
-    let path = path.into();
-
-    // Relative paths are resolved relative to the file in which they are found
-    // after macro expansion (that is, they are unhygienic).
-    if !path.is_absolute() {
-        let callsite = span.source_callsite();
-        let mut result = match map.span_to_unmapped_path(callsite) {
-            FileName::Real(path) => path,
-            FileName::DocTest(path, _) => path,
-            other => panic!("cannot resolve relative path in non-file source `{}`", other),
-        };
-        result.pop();
-        result.push(path);
-        result
-    } else {
-        path
-    }
-}

From 7c42259d03b196839754ef2c55d6e3acb3c9f895 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Wed, 17 Jul 2019 22:46:37 +0200
Subject: [PATCH 6/7] Update stdarch submodule

---
 src/stdarch | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/stdarch b/src/stdarch
index b881a2d124cb0..4791ba85e7645 160000
--- a/src/stdarch
+++ b/src/stdarch
@@ -1 +1 @@
-Subproject commit b881a2d124cb0eea09d137300eb4a35829b517fb
+Subproject commit 4791ba85e7645c02146dd416288480943670d1ca

From 218ab4cd7fdf145a0870c582a23ad5fd85cd80e5 Mon Sep 17 00:00:00 2001
From: Jonas Schievink <jonasschievink@gmail.com>
Date: Tue, 23 Jul 2019 17:57:54 +0200
Subject: [PATCH 7/7] Update test

---
 src/test/ui/extern/external-doc-error.rs     |  1 -
 src/test/ui/extern/external-doc-error.stderr | 12 +++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/src/test/ui/extern/external-doc-error.rs b/src/test/ui/extern/external-doc-error.rs
index e17dda65568e9..4e89f7464da49 100644
--- a/src/test/ui/extern/external-doc-error.rs
+++ b/src/test/ui/extern/external-doc-error.rs
@@ -4,7 +4,6 @@
 
 #[doc(include = "not-a-file.md")]
 pub struct SomeStruct; //~^ ERROR couldn't read
-                       //~| HELP external doc paths are relative to the crate root
 
 #[doc(include = "auxiliary/invalid-utf8.txt")]
 pub struct InvalidUtf8; //~^ ERROR wasn't a utf-8 file
diff --git a/src/test/ui/extern/external-doc-error.stderr b/src/test/ui/extern/external-doc-error.stderr
index a3be3277de545..b180cd66c5269 100644
--- a/src/test/ui/extern/external-doc-error.stderr
+++ b/src/test/ui/extern/external-doc-error.stderr
@@ -3,35 +3,33 @@ error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2)
    |
 LL | #[doc(include = "not-a-file.md")]
    |                 ^^^^^^^^^^^^^^^ couldn't read file
-   |
-   = help: external doc paths are relative to the crate root
 
 error: $DIR/auxiliary/invalid-utf8.txt wasn't a utf-8 file
-  --> $DIR/external-doc-error.rs:9:17
+  --> $DIR/external-doc-error.rs:8:17
    |
 LL | #[doc(include = "auxiliary/invalid-utf8.txt")]
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid utf-8
 
 error: expected path to external documentation
-  --> $DIR/external-doc-error.rs:12:7
+  --> $DIR/external-doc-error.rs:11:7
    |
 LL | #[doc(include)]
    |       ^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
 
 error: expected path to external documentation
-  --> $DIR/external-doc-error.rs:17:7
+  --> $DIR/external-doc-error.rs:16:7
    |
 LL | #[doc(include("../README.md"))]
    |       ^^^^^^^^^^^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "../README.md"`
 
 error: expected path to external documentation
-  --> $DIR/external-doc-error.rs:22:7
+  --> $DIR/external-doc-error.rs:21:7
    |
 LL | #[doc(include = 123)]
    |       ^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
 
 error: expected path to external documentation
-  --> $DIR/external-doc-error.rs:27:7
+  --> $DIR/external-doc-error.rs:26:7
    |
 LL | #[doc(include(123))]
    |       ^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`