about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-12-06 01:36:51 +0000
committerbors <bors@rust-lang.org>2018-12-06 01:36:51 +0000
commit1839c144bc6db8c07945caacd449aa7f3a76cd47 (patch)
treee9bcbb9af70c5861b071456fce4071f22f75a01c
parent4988b096e673204b91683dc693fc3eb6b2323e97 (diff)
parentf0f8aa9e05726bfbc065fa2504daf3232f29bc03 (diff)
downloadrust-1839c144bc6db8c07945caacd449aa7f3a76cd47.tar.gz
rust-1839c144bc6db8c07945caacd449aa7f3a76cd47.zip
Auto merge of #54517 - mcr431:53956-panic-on-include_bytes-of-own-file, r=michaelwoerister
53956 panic on include bytes of own file

fix #53956

When using `include_bytes!` on a source file in the project, compiler would panic on subsequent compilations because `expand_include_bytes` would overwrite files in the source_map with no source. This PR changes `expand_include_bytes` to check source_map and use the already existing src, if any.
-rw-r--r--src/librustc/ich/impls_syntax.rs15
-rw-r--r--src/librustc/session/config.rs4
-rw-r--r--src/librustc_driver/lib.rs2
-rw-r--r--src/librustc_driver/test.rs2
-rw-r--r--src/librustc_errors/emitter.rs7
-rw-r--r--src/librustc_errors/lib.rs2
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/test.rs18
-rw-r--r--src/libsyntax/attr/mod.rs2
-rw-r--r--src/libsyntax/ext/quote.rs8
-rw-r--r--src/libsyntax/ext/source_util.rs10
-rw-r--r--src/libsyntax/parse/lexer/mod.rs2
-rw-r--r--src/libsyntax/parse/mod.rs10
-rw-r--r--src/libsyntax/parse/token.rs13
-rw-r--r--src/libsyntax/source_map.rs92
-rw-r--r--src/libsyntax_ext/proc_macro_server.rs2
-rw-r--r--src/libsyntax_pos/lib.rs93
-rw-r--r--src/test/run-make-fulldeps/issue-19371/foo.rs3
-rw-r--r--src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs2
-rw-r--r--src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs6
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.stdout4
21 files changed, 180 insertions, 119 deletions
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index b629fb820b3..439c6e42e1a 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -417,13 +417,14 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
 impl_stable_hash_for!(enum ::syntax_pos::FileName {
     Real(pb),
     Macros(s),
-    QuoteExpansion,
-    Anon,
-    MacroExpansion,
-    ProcMacroSourceCode,
-    CliCrateAttr,
-    CfgSpec,
-    Custom(s)
+    QuoteExpansion(s),
+    Anon(s),
+    MacroExpansion(s),
+    ProcMacroSourceCode(s),
+    CliCrateAttr(s),
+    CfgSpec(s),
+    Custom(s),
+    DocTest(pb, line),
 });
 
 impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 480d4a8e48f..c9866230cdd 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1756,8 +1756,8 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> ast::CrateConfig {
         .into_iter()
         .map(|s| {
             let sess = parse::ParseSess::new(FilePathMapping::empty());
-            let mut parser =
-                parse::new_parser_from_source_str(&sess, FileName::CfgSpec, s.to_string());
+            let filename = FileName::cfg_spec_source_code(&s);
+            let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string());
 
             macro_rules! error {($reason: expr) => {
                 early_error(ErrorOutputType::default(),
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 061c19eca36..45d107f13a0 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -594,7 +594,7 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option
             } else {
                 None
             };
-            Some((Input::Str { name: FileName::Anon, input: src },
+            Some((Input::Str { name: FileName::anon_source_code(&src), input: src },
                   None, err))
         } else {
             Some((Input::File(PathBuf::from(ifile)),
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 8865c7e438e..b8cd9bda7f0 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -129,7 +129,7 @@ fn test_env_with_pool<F>(
     let cstore = CStore::new(::get_codegen_backend(&sess).metadata_loader());
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     let input = config::Input::Str {
-        name: FileName::Anon,
+        name: FileName::anon_source_code(&source_string),
         input: source_string.to_string(),
     };
     let krate =
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 7e69e98071d..ab2ab25c91a 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -1044,7 +1044,7 @@ impl EmitterWriter {
                     buffer.append(buffer_msg_line_offset,
                                   &format!("{}:{}:{}",
                                            loc.file.name,
-                                           sm.doctest_offset_line(loc.line),
+                                           sm.doctest_offset_line(&loc.file.name, loc.line),
                                            loc.col.0 + 1),
                                   Style::LineAndColumn);
                     for _ in 0..max_line_num_len {
@@ -1054,7 +1054,7 @@ impl EmitterWriter {
                     buffer.prepend(0,
                                    &format!("{}:{}:{}: ",
                                             loc.file.name,
-                                            sm.doctest_offset_line(loc.line),
+                                            sm.doctest_offset_line(&loc.file.name, loc.line),
                                             loc.col.0 + 1),
                                    Style::LineAndColumn);
                 }
@@ -1075,7 +1075,8 @@ impl EmitterWriter {
                     };
                     format!("{}:{}{}",
                             annotated_file.file.name,
-                            sm.doctest_offset_line(first_line.line_index),
+                            sm.doctest_offset_line(
+                                &annotated_file.file.name, first_line.line_index),
                             col)
                 } else {
                     annotated_file.file.name.to_string()
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 0fb77a7a3ab..b6528cbe2c8 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -130,7 +130,7 @@ pub trait SourceMapper {
     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
     fn call_span_if_macro(&self, sp: Span) -> Span;
     fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool;
-    fn doctest_offset_line(&self, line: usize) -> usize;
+    fn doctest_offset_line(&self, file: &FileName, line: usize) -> usize;
 }
 
 impl CodeSuggestion {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1d903476f16..5276683648d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3008,7 +3008,7 @@ pub struct Span {
 impl Span {
     pub fn empty() -> Span {
         Span {
-            filename: FileName::Anon,
+            filename: FileName::Anon(0),
             loline: 0, locol: 0,
             hiline: 0, hicol: 0,
         }
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index d9bab91fd0c..74583196818 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -197,8 +197,14 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
     let (test, line_offset) = 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 SourceMap::span_to_unmapped_path
+
+    let path = match filename {
+        FileName::Real(path) => path.clone(),
+        _ => PathBuf::from(r"doctest.rs"),
+    };
+
     let input = config::Input::Str {
-        name: filename.to_owned(),
+        name: FileName::DocTest(path, line as isize - line_offset as isize),
         input: test,
     };
     let outputs = OutputTypes::new(&[(OutputType::Exe, None)]);
@@ -252,9 +258,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
     let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
 
     let (libdir, outdir, compile_result) = driver::spawn_thread_pool(sessopts, |sessopts| {
-        let source_map = Lrc::new(SourceMap::new_doctest(
-            sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
-        ));
+        let source_map = Lrc::new(SourceMap::new(sessopts.file_path_mapping()));
         let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
                                                         Some(source_map.clone()),
                                                         false,
@@ -401,7 +405,7 @@ pub fn make_test(s: &str,
         use errors::emitter::EmitterWriter;
         use errors::Handler;
 
-        let filename = FileName::Anon;
+        let filename = FileName::anon_source_code(s);
         let source = crates + &everything_else;
 
         // any errors in parsing should also appear when the doctest is compiled for real, so just
@@ -411,8 +415,6 @@ pub fn make_test(s: &str,
         let handler = Handler::with_emitter(false, false, box emitter);
         let sess = ParseSess::with_span_handler(handler, cm);
 
-        debug!("about to parse: \n{}", source);
-
         let mut found_main = false;
         let mut found_extern_crate = cratename.is_none();
 
@@ -487,8 +489,6 @@ pub fn make_test(s: &str,
         prog.push_str("\n}");
     }
 
-    info!("final test program: {}", prog);
-
     (prog, line_offset)
 }
 
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index 64876659477..518b34eefa8 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -803,7 +803,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
     for raw_attr in attrs {
         let mut parser = parse::new_parser_from_source_str(
             parse_sess,
-            FileName::CliCrateAttr,
+            FileName::cli_crate_attr_source_code(&raw_attr),
             raw_attr.clone(),
         );
 
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index 69ed318b049..91818992fe1 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -353,27 +353,27 @@ pub mod rt {
     impl<'a> ExtParseUtils for ExtCtxt<'a> {
         fn parse_item(&self, s: String) -> P<ast::Item> {
             panictry!(parse::parse_item_from_source_str(
-                FileName::QuoteExpansion,
+                FileName::quote_expansion_source_code(&s),
                 s,
                 self.parse_sess())).expect("parse error")
         }
 
         fn parse_stmt(&self, s: String) -> ast::Stmt {
             panictry!(parse::parse_stmt_from_source_str(
-                FileName::QuoteExpansion,
+                FileName::quote_expansion_source_code(&s),
                 s,
                 self.parse_sess())).expect("parse error")
         }
 
         fn parse_expr(&self, s: String) -> P<ast::Expr> {
             panictry!(parse::parse_expr_from_source_str(
-                FileName::QuoteExpansion,
+                FileName::quote_expansion_source_code(&s),
                 s,
                 self.parse_sess()))
         }
 
         fn parse_tts(&self, s: String) -> Vec<TokenTree> {
-            let source_name = FileName::QuoteExpansion;
+            let source_name = FileName::quote_expansion_source_code(&s);
             parse::parse_stream_from_source_str(source_name, s, self.parse_sess(), None)
                 .into_trees().collect()
         }
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index e1ba8897a47..75e25083d03 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -182,9 +182,12 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke
             DummyResult::expr(sp)
         }
         Ok(..) => {
-            // Add this input file to the code map to make it available as
-            // dependency information, but don't enter it's contents
-            cx.source_map().new_source_file(file.into(), String::new());
+            let src = match String::from_utf8(bytes.clone()) {
+                Ok(contents) => contents,
+                Err(..) => "".to_string()
+            };
+
+            cx.source_map().new_source_file(file.into(), src);
 
             base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes))))
         }
@@ -201,6 +204,7 @@ fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: String) -> PathBuf
         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();
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 0c8e81a0ee6..80227fdf82d 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -1900,7 +1900,7 @@ mod tests {
                  sess: &'a ParseSess,
                  teststr: String)
                  -> StringReader<'a> {
-        let sf = sm.new_source_file(PathBuf::from("zebra.rs").into(), teststr);
+        let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr);
         StringReader::new(sess, sf, None)
     }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 58068ce5f60..866dba24dcb 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -974,23 +974,25 @@ mod tests {
         with_globals(|| {
             let sess = ParseSess::new(FilePathMapping::empty());
 
-            let name = FileName::Custom("source".to_string());
+            let name_1 = FileName::Custom("crlf_source_1".to_string());
             let source = "/// doc comment\r\nfn foo() {}".to_string();
-            let item = parse_item_from_source_str(name.clone(), source, &sess)
+            let item = parse_item_from_source_str(name_1, source, &sess)
                 .unwrap().unwrap();
             let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
             assert_eq!(doc, "/// doc comment");
 
+            let name_2 = FileName::Custom("crlf_source_2".to_string());
             let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
-            let item = parse_item_from_source_str(name.clone(), source, &sess)
+            let item = parse_item_from_source_str(name_2, source, &sess)
                 .unwrap().unwrap();
             let docs = item.attrs.iter().filter(|a| a.path == "doc")
                         .map(|a| a.value_str().unwrap().to_string()).collect::<Vec<_>>();
             let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()];
             assert_eq!(&docs[..], b);
 
+            let name_3 = FileName::Custom("clrf_source_3".to_string());
             let source = "/** doc comment\r\n *  with CRLF */\r\nfn foo() {}".to_string();
-            let item = parse_item_from_source_str(name, source, &sess).unwrap().unwrap();
+            let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap();
             let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
             assert_eq!(doc, "/** doc comment\n *  with CRLF */");
         });
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 4a5f3e240da..04a791fbcb9 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -545,7 +545,8 @@ impl Token {
         let tokens_for_real = nt.1.force(|| {
             // FIXME(#43081): Avoid this pretty-print + reparse hack
             let source = pprust::token_to_string(self);
-            parse_stream_from_source_str(FileName::MacroExpansion, source, sess, Some(span))
+            let filename = FileName::macro_expansion_source_code(&source);
+            parse_stream_from_source_str(filename, source, sess, Some(span))
         });
 
         // During early phases of the compiler the AST could get modified
@@ -781,10 +782,12 @@ fn prepend_attrs(sess: &ParseSess,
         assert_eq!(attr.style, ast::AttrStyle::Outer,
                    "inner attributes should prevent cached tokens from existing");
 
+        let source = pprust::attr_to_string(attr);
+        let macro_filename = FileName::macro_expansion_source_code(&source);
         if attr.is_sugared_doc {
             let stream = parse_stream_from_source_str(
-                FileName::MacroExpansion,
-                pprust::attr_to_string(attr),
+                macro_filename,
+                source,
                 sess,
                 Some(span),
             );
@@ -805,8 +808,8 @@ fn prepend_attrs(sess: &ParseSess,
         // should eventually be removed.
         } else {
             let stream = parse_stream_from_source_str(
-                FileName::MacroExpansion,
-                pprust::path_to_string(&attr.path),
+                macro_filename,
+                source,
                 sess,
                 Some(span),
             );
diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs
index e8cacc3b5af..ee60d2dd615 100644
--- a/src/libsyntax/source_map.rs
+++ b/src/libsyntax/source_map.rs
@@ -110,11 +110,19 @@ pub struct StableSourceFileId(u128);
 
 impl StableSourceFileId {
     pub fn new(source_file: &SourceFile) -> StableSourceFileId {
+        StableSourceFileId::new_from_pieces(&source_file.name,
+                                         source_file.name_was_remapped,
+                                         source_file.unmapped_path.as_ref())
+    }
+
+    pub fn new_from_pieces(name: &FileName,
+                           name_was_remapped: bool,
+                           unmapped_path: Option<&FileName>) -> StableSourceFileId {
         let mut hasher = StableHasher::new();
 
-        source_file.name.hash(&mut hasher);
-        source_file.name_was_remapped.hash(&mut hasher);
-        source_file.unmapped_path.hash(&mut hasher);
+        name.hash(&mut hasher);
+        name_was_remapped.hash(&mut hasher);
+        unmapped_path.hash(&mut hasher);
 
         StableSourceFileId(hasher.finish())
     }
@@ -136,9 +144,6 @@ pub struct SourceMap {
     // This is used to apply the file path remapping as specified via
     // --remap-path-prefix to all SourceFiles allocated within this SourceMap.
     path_mapping: FilePathMapping,
-    /// In case we are in a doctest, replace all file names with the PathBuf,
-    /// and add the given offsets to the line info
-    doctest_offset: Option<(FileName, isize)>,
 }
 
 impl SourceMap {
@@ -147,17 +152,7 @@ impl SourceMap {
             files: Default::default(),
             file_loader: Box::new(RealFileLoader),
             path_mapping,
-            doctest_offset: None,
-        }
-    }
-
-    pub fn new_doctest(path_mapping: FilePathMapping,
-                       file: FileName, line: isize) -> SourceMap {
-        SourceMap {
-            doctest_offset: Some((file, line)),
-            ..SourceMap::new(path_mapping)
         }
-
     }
 
     pub fn with_file_loader(file_loader: Box<dyn FileLoader + Sync + Send>,
@@ -167,7 +162,6 @@ impl SourceMap {
             files: Default::default(),
             file_loader: file_loader,
             path_mapping,
-            doctest_offset: None,
         }
     }
 
@@ -181,11 +175,7 @@ impl SourceMap {
 
     pub fn load_file(&self, path: &Path) -> io::Result<Lrc<SourceFile>> {
         let src = self.file_loader.read_file(path)?;
-        let filename = if let Some((ref name, _)) = self.doctest_offset {
-            name.clone()
-        } else {
-            path.to_owned().into()
-        };
+        let filename = path.to_owned().into();
         Ok(self.new_source_file(filename, src))
     }
 
@@ -208,7 +198,8 @@ impl SourceMap {
     }
 
     /// Creates a new source_file.
-    /// This does not ensure that only one SourceFile exists per file name.
+    /// If a file already exists in the source_map with the same id, that file is returned
+    /// unmodified
     pub fn new_source_file(&self, filename: FileName, src: String) -> Lrc<SourceFile> {
         let start_pos = self.next_start_pos();
 
@@ -226,21 +217,30 @@ impl SourceMap {
             },
             other => (other, false),
         };
-        let source_file = Lrc::new(SourceFile::new(
-            filename,
-            was_remapped,
-            unmapped_path,
-            src,
-            Pos::from_usize(start_pos),
-        ));
 
-        let mut files = self.files.borrow_mut();
+        let file_id = StableSourceFileId::new_from_pieces(&filename,
+                                                       was_remapped,
+                                                       Some(&unmapped_path));
 
-        files.source_files.push(source_file.clone());
-        files.stable_id_to_source_file.insert(StableSourceFileId::new(&source_file),
-                                              source_file.clone());
+        return match self.source_file_by_stable_id(file_id) {
+            Some(lrc_sf) => lrc_sf,
+            None => {
+                let source_file = Lrc::new(SourceFile::new(
+                    filename,
+                    was_remapped,
+                    unmapped_path,
+                    src,
+                    Pos::from_usize(start_pos),
+                ));
 
-        source_file
+                let mut files = self.files.borrow_mut();
+
+                files.source_files.push(source_file.clone());
+                files.stable_id_to_source_file.insert(file_id, source_file.clone());
+
+                source_file
+            }
+        }
     }
 
     /// Allocates a new SourceFile representing a source file from an external
@@ -310,15 +310,17 @@ impl SourceMap {
     }
 
     // If there is a doctest_offset, apply it to the line
-    pub fn doctest_offset_line(&self, mut orig: usize) -> usize {
-        if let Some((_, line)) = self.doctest_offset {
-            if line >= 0 {
-                orig = orig + line as usize;
-            } else {
-                orig = orig - (-line) as usize;
-            }
+    pub fn doctest_offset_line(&self, file: &FileName, orig: usize) -> usize {
+        return match file {
+            FileName::DocTest(_, offset) => {
+                return if *offset >= 0 {
+                    orig + *offset as usize
+                } else {
+                    orig - (-(*offset)) as usize
+                }
+            },
+            _ => orig
         }
-        orig
     }
 
     /// Lookup source information about a BytePos
@@ -983,8 +985,8 @@ impl SourceMapper for SourceMap {
             }
         )
     }
-    fn doctest_offset_line(&self, line: usize) -> usize {
-        self.doctest_offset_line(line)
+    fn doctest_offset_line(&self, file: &FileName, line: usize) -> usize {
+        self.doctest_offset_line(file, line)
     }
 }
 
diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs
index 4babc2e612f..6c7da589a42 100644
--- a/src/libsyntax_ext/proc_macro_server.rs
+++ b/src/libsyntax_ext/proc_macro_server.rs
@@ -402,7 +402,7 @@ impl server::TokenStream for Rustc<'_> {
     }
     fn from_str(&mut self, src: &str) -> Self::TokenStream {
         parse::parse_stream_from_source_str(
-            FileName::ProcMacroSourceCode,
+            FileName::proc_macro_source_code(src.clone()),
             src.to_string(),
             self.sess,
             Some(self.call_site),
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 34fb71e4ddf..4d42b85ea75 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -90,19 +90,20 @@ pub enum FileName {
     /// A macro.  This includes the full name of the macro, so that there are no clashes.
     Macros(String),
     /// call to `quote!`
-    QuoteExpansion,
+    QuoteExpansion(u64),
     /// Command line
-    Anon,
+    Anon(u64),
     /// Hack in src/libsyntax/parse.rs
     /// FIXME(jseyfried)
-    MacroExpansion,
-    ProcMacroSourceCode,
+    MacroExpansion(u64),
+    ProcMacroSourceCode(u64),
     /// Strings provided as --cfg [cfgspec] stored in a crate_cfg
-    CfgSpec,
+    CfgSpec(u64),
     /// Strings provided as crate attributes in the CLI
-    CliCrateAttr,
+    CliCrateAttr(u64),
     /// Custom sources for explicit parser calls from plugins and drivers
     Custom(String),
+    DocTest(PathBuf, isize),
 }
 
 impl std::fmt::Display for FileName {
@@ -111,13 +112,15 @@ impl std::fmt::Display for FileName {
         match *self {
             Real(ref path) => write!(fmt, "{}", path.display()),
             Macros(ref name) => write!(fmt, "<{} macros>", name),
-            QuoteExpansion => write!(fmt, "<quote expansion>"),
-            MacroExpansion => write!(fmt, "<macro expansion>"),
-            Anon => write!(fmt, "<anon>"),
-            ProcMacroSourceCode => write!(fmt, "<proc-macro source code>"),
-            CfgSpec => write!(fmt, "cfgspec"),
-            CliCrateAttr => write!(fmt, "<crate attribute>"),
+            QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
+            MacroExpansion(_) => write!(fmt, "<macro expansion>"),
+            Anon(_) => write!(fmt, "<anon>"),
+            ProcMacroSourceCode(_) =>
+                write!(fmt, "<proc-macro source code>"),
+            CfgSpec(_) => write!(fmt, "<cfgspec>"),
+            CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
             Custom(ref s) => write!(fmt, "<{}>", s),
+            DocTest(ref path, _) => write!(fmt, "{}", path.display()),
         }
     }
 }
@@ -135,13 +138,14 @@ impl FileName {
         match *self {
             Real(_) => true,
             Macros(_) |
-            Anon |
-            MacroExpansion |
-            ProcMacroSourceCode |
-            CfgSpec |
-            CliCrateAttr |
+            Anon(_) |
+            MacroExpansion(_) |
+            ProcMacroSourceCode(_) |
+            CfgSpec(_) |
+            CliCrateAttr(_) |
             Custom(_) |
-            QuoteExpansion => false,
+            QuoteExpansion(_) |
+            DocTest(_, _) => false,
         }
     }
 
@@ -149,16 +153,57 @@ impl FileName {
         use self::FileName::*;
         match *self {
             Real(_) |
-            Anon |
-            MacroExpansion |
-            ProcMacroSourceCode |
-            CfgSpec |
-            CliCrateAttr |
+            Anon(_) |
+            MacroExpansion(_) |
+            ProcMacroSourceCode(_) |
+            CfgSpec(_) |
+            CliCrateAttr(_) |
             Custom(_) |
-            QuoteExpansion => false,
+            QuoteExpansion(_) |
+            DocTest(_, _) => false,
             Macros(_) => true,
         }
     }
+
+    pub fn quote_expansion_source_code(src: &str) -> FileName {
+        let mut hasher = StableHasher::new();
+        src.hash(&mut hasher);
+        FileName::QuoteExpansion(hasher.finish())
+    }
+
+    pub fn macro_expansion_source_code(src: &str) -> FileName {
+        let mut hasher = StableHasher::new();
+        src.hash(&mut hasher);
+        FileName::MacroExpansion(hasher.finish())
+    }
+
+    pub fn anon_source_code(src: &str) -> FileName {
+        let mut hasher = StableHasher::new();
+        src.hash(&mut hasher);
+        FileName::Anon(hasher.finish())
+    }
+
+    pub fn proc_macro_source_code(src: &str) -> FileName {
+        let mut hasher = StableHasher::new();
+        src.hash(&mut hasher);
+        FileName::ProcMacroSourceCode(hasher.finish())
+    }
+
+    pub fn cfg_spec_source_code(src: &str) -> FileName {
+        let mut hasher = StableHasher::new();
+        src.hash(&mut hasher);
+        FileName::QuoteExpansion(hasher.finish())
+    }
+
+    pub fn cli_crate_attr_source_code(src: &str) -> FileName {
+        let mut hasher = StableHasher::new();
+        src.hash(&mut hasher);
+        FileName::CliCrateAttr(hasher.finish())
+    }
+
+    pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName{
+        FileName::DocTest(path, line)
+    }
 }
 
 /// Spans represent a region of code, used for error reporting. Positions in spans
diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs
index 4dfecb33c14..c342e1c4835 100644
--- a/src/test/run-make-fulldeps/issue-19371/foo.rs
+++ b/src/test/run-make-fulldeps/issue-19371/foo.rs
@@ -72,7 +72,8 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         driver::spawn_thread_pool(opts, |opts| {
             let (sess, cstore, codegen_backend) = basic_sess(opts);
             let control = CompileController::basic();
-            let input = Input::Str { name: FileName::Anon, input: code };
+            let name = FileName::anon_source_code(&code);
+            let input = Input::Str { name, input: code };
             let _ = compile_input(
                 codegen_backend,
                 &sess,
diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
index f7fa2798051..c9d03294843 100644
--- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
+++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
@@ -32,7 +32,7 @@ use std::fmt;
 // Copied out of syntax::util::parser_testing
 
 pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> {
-    new_parser_from_source_str(ps, FileName::Custom("bogofile".to_owned()), source_str)
+    new_parser_from_source_str(ps, FileName::Custom(source_str.clone()), source_str)
 }
 
 fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> PResult<'a, T> where
diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
index e944ef2b620..854063a2984 100644
--- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
@@ -44,9 +44,11 @@ use syntax::ptr::P;
 
 
 fn parse_expr(ps: &ParseSess, src: &str) -> P<Expr> {
+    let src_as_string = src.to_string();
+
     let mut p = parse::new_parser_from_source_str(ps,
-                                                  FileName::Custom("expr".to_owned()),
-                                                  src.to_owned());
+                                                  FileName::Custom(src_as_string.clone()),
+                                                  src_as_string);
     p.parse_expr().unwrap()
 }
 
diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout
index cab7bda6c67..52e0cdca950 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-output.stdout
@@ -12,7 +12,7 @@ error[E0425]: cannot find value `no` in this scope
 3 | no
   | ^^ not found in this scope
 
-thread '$DIR/failed-doctest-output.rs - OtherStruct (line 27)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:323:13
+thread '$DIR/failed-doctest-output.rs - OtherStruct (line 27)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:327:13
 note: Run with `RUST_BACKTRACE=1` for a backtrace.
 
 ---- $DIR/failed-doctest-output.rs - SomeStruct (line 21) stdout ----
@@ -21,7 +21,7 @@ thread '$DIR/failed-doctest-output.rs - SomeStruct (line 21)' panicked at 'test
 thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1
 note: Run with `RUST_BACKTRACE=1` for a backtrace.
 
-', src/librustdoc/test.rs:358:17
+', src/librustdoc/test.rs:362:17
 
 
 failures: