From 9a2ee0aaef1dfe835c65359b2b07721953ea7040 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Thu, 2 May 2019 05:05:58 +0300
Subject: [PATCH 1/5] serialize: add missing Encodable impl for Path.

---
 src/libserialize/serialize.rs | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs
index 8ef8c2b4c0a22..36a1628014ddb 100644
--- a/src/libserialize/serialize.rs
+++ b/src/libserialize/serialize.rs
@@ -764,12 +764,18 @@ macro_rules! tuple {
 
 tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
 
-impl Encodable for path::PathBuf {
+impl Encodable for path::Path {
     fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
         self.to_str().unwrap().encode(e)
     }
 }
 
+impl Encodable for path::PathBuf {
+    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
+        path::Path::encode(self, e)
+    }
+}
+
 impl Decodable for path::PathBuf {
     fn decode<D: Decoder>(d: &mut D) -> Result<path::PathBuf, D::Error> {
         let bytes: String = Decodable::decode(d)?;

From f0e43fc98671f76f7cdcc07cfa17fb2362c132ea Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Thu, 2 May 2019 05:06:08 +0300
Subject: [PATCH 2/5] compiletest: only use `make_exe_name` for tests that end
 up being executed.

---
 .../const-eval/unused-broken-const.stderr     |  2 --
 src/test/ui/emit-directives.rs                |  6 -----
 src/test/ui/emit-directives.stderr            |  2 +-
 ...n-projection-output-repeated-supertrait.rs |  3 +++
 src/tools/compiletest/src/runtest.rs          | 26 +++++++++++++++----
 5 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/src/test/ui/consts/const-eval/unused-broken-const.stderr b/src/test/ui/consts/const-eval/unused-broken-const.stderr
index 603efe449f143..e45ce65d8bb35 100644
--- a/src/test/ui/consts/const-eval/unused-broken-const.stderr
+++ b/src/test/ui/consts/const-eval/unused-broken-const.stderr
@@ -1,5 +1,3 @@
-warning: due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
-
 error: any use of this value will cause an error
   --> $DIR/unused-broken-const.rs:5:18
    |
diff --git a/src/test/ui/emit-directives.rs b/src/test/ui/emit-directives.rs
index 088280e358ae7..924569d3e232d 100644
--- a/src/test/ui/emit-directives.rs
+++ b/src/test/ui/emit-directives.rs
@@ -1,11 +1,5 @@
-// ignore-tidy-linelength
 // compile-flags:--emit=metadata --error-format=json -Z emit-directives
 // compile-pass
-//
-// Normalization is required to eliminated minor path and filename differences
-// across platforms.
-// normalize-stderr-test: "metadata file written: .*/emit-directives" -> "metadata file written: .../emit-directives"
-// normalize-stderr-test: "emit-directives(\.\w*)?/a(\.\w*)?" -> "emit-directives/a"
 
 // A very basic test for the emission of build directives in JSON output.
 
diff --git a/src/test/ui/emit-directives.stderr b/src/test/ui/emit-directives.stderr
index b8a4b96f4bf25..068745edb8dc0 100644
--- a/src/test/ui/emit-directives.stderr
+++ b/src/test/ui/emit-directives.stderr
@@ -1 +1 @@
-{"directive":"metadata file written: .../emit-directives/a"}
+{"directive":"metadata file written: $TEST_BUILD_DIR/emit-directives/libemit_directives.rmeta"}
diff --git a/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs b/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs
index 46c083f930591..3e9f612a2afee 100644
--- a/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs
+++ b/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs
@@ -1,5 +1,8 @@
 // compile-pass
 
+// FIXME(eddyb) shorten the name so windows doesn't choke on it.
+#![crate_name = "trait_test"]
+
 // Regression test related to #56288. Check that a supertrait projection (of
 // `Output`) that references `Self` is ok if there is another occurence of
 // the same supertrait that specifies the projection explicitly, even if
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 42f9cdb7886fd..649679e9b3cc0 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1422,10 +1422,21 @@ impl<'test> TestCx<'test> {
     }
 
     fn compile_test(&self) -> ProcRes {
-        let mut rustc = self.make_compile_args(
-            &self.testpaths.file,
-            TargetLocation::ThisFile(self.make_exe_name()),
-        );
+        // Only use `make_exe_name` when the test ends up being executed.
+        let will_execute = match self.config.mode {
+            RunPass | Ui => self.should_run_successfully(),
+            Incremental => self.revision.unwrap().starts_with("r"),
+            RunFail | RunPassValgrind | MirOpt |
+            DebugInfoBoth | DebugInfoGdb | DebugInfoLldb => true,
+            _ => false,
+        };
+        let output_file = if will_execute {
+            TargetLocation::ThisFile(self.make_exe_name())
+        } else {
+            TargetLocation::ThisDirectory(self.output_base_dir())
+        };
+
+        let mut rustc = self.make_compile_args(&self.testpaths.file, output_file);
 
         rustc.arg("-L").arg(&self.aux_output_dir_name());
 
@@ -1882,7 +1893,12 @@ impl<'test> TestCx<'test> {
                 rustc.arg("-o").arg(path);
             }
             TargetLocation::ThisDirectory(path) => {
-                rustc.arg("--out-dir").arg(path);
+                if is_rustdoc {
+                    // `rustdoc` uses `-o` for the output directory.
+                    rustc.arg("-o").arg(path);
+                } else {
+                    rustc.arg("--out-dir").arg(path);
+                }
             }
         }
 

From 1618c079abc7cb97afe3cbcf5a7ff1f9412775bc Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Thu, 2 May 2019 05:06:33 +0300
Subject: [PATCH 3/5] rustc: rename -Z emit-directives to -Z
 emit-artifact-notifications and simplify the output.

---
 src/librustc/session/config.rs                 |  4 ++--
 src/librustc_errors/emitter.rs                 |  8 +++++---
 src/librustc_errors/lib.rs                     | 18 ++++++------------
 src/librustc_interface/passes.rs               | 13 +++++--------
 src/libsyntax/json.rs                          | 13 +++++++------
 .../ui/emit-artifact-notifications.nll.stderr  |  1 +
 src/test/ui/emit-artifact-notifications.rs     |  6 ++++++
 src/test/ui/emit-artifact-notifications.stderr |  1 +
 src/test/ui/emit-directives.rs                 |  6 ------
 src/test/ui/emit-directives.stderr             |  1 -
 src/tools/compiletest/src/json.rs              | 10 +++++-----
 11 files changed, 38 insertions(+), 43 deletions(-)
 create mode 100644 src/test/ui/emit-artifact-notifications.nll.stderr
 create mode 100644 src/test/ui/emit-artifact-notifications.rs
 create mode 100644 src/test/ui/emit-artifact-notifications.stderr
 delete mode 100644 src/test/ui/emit-directives.rs
 delete mode 100644 src/test/ui/emit-directives.stderr

diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 084a5429f26fa..12427daa38381 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1462,8 +1462,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
          the same values as the target option of the same name"),
     allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
         "only allow the listed language features to be enabled in code (space separated)"),
-    emit_directives: bool = (false, parse_bool, [UNTRACKED],
-        "emit build directives if producing JSON output"),
+    emit_artifact_notifications: bool = (false, parse_bool, [UNTRACKED],
+        "emit notifications after each artifact has been output (only in the JSON format)"),
 }
 
 pub fn default_lib_output() -> CrateType {
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index bfc9113c2d41e..59cbd65f05c68 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -16,6 +16,7 @@ use std::borrow::Cow;
 use std::io::prelude::*;
 use std::io;
 use std::cmp::{min, Reverse};
+use std::path::Path;
 use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi};
 use termcolor::{WriteColor, Color, Buffer};
 
@@ -52,9 +53,10 @@ pub trait Emitter {
     /// Emit a structured diagnostic.
     fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>);
 
-    /// Emit a JSON directive. The default is to do nothing; this should only
-    /// be emitted with --error-format=json.
-    fn maybe_emit_json_directive(&mut self, _directive: String) {}
+    /// Emit a notification that an artifact has been output.
+    /// This is currently only supported for the JSON format,
+    /// other formats can, and will, simply ignore it.
+    fn emit_artifact_notification(&mut self, _path: &Path) {}
 
     /// Checks if should show explanations about "rustc --explain"
     fn should_show_explain(&self) -> bool {
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index e173e1060cc10..3aa87fad07174 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -26,6 +26,7 @@ use std::borrow::Cow;
 use std::cell::Cell;
 use std::{error, fmt};
 use std::panic;
+use std::path::Path;
 
 use termcolor::{ColorSpec, Color};
 
@@ -294,16 +295,9 @@ impl error::Error for ExplicitBug {
 pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId};
 pub use diagnostic_builder::DiagnosticBuilder;
 
-/// A handler deals with two kinds of compiler output.
-/// - Errors: certain errors (fatal, bug, unimpl) may cause immediate exit,
-///   others log errors for later reporting.
-/// - Directives: with --error-format=json, the compiler produces directives
-///   that indicate when certain actions have completed, which are useful for
-///   Cargo. They may change at any time and should not be considered a public
-///   API.
-///
-/// This crate's name (rustc_errors) doesn't encompass the directives, because
-/// directives were added much later.
+/// A handler deals with errors and other compiler output.
+/// Certain errors (fatal, bug, unimpl) may cause immediate exit,
+/// others log errors for later reporting.
 pub struct Handler {
     pub flags: HandlerFlags,
 
@@ -775,8 +769,8 @@ impl Handler {
         }
     }
 
-    pub fn maybe_emit_json_directive(&self, directive: String) {
-        self.emitter.borrow_mut().maybe_emit_json_directive(directive);
+    pub fn emit_artifact_notification(&self, path: &Path) {
+        self.emitter.borrow_mut().emit_artifact_notification(path);
     }
 }
 
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 8543cca1dd545..54b3e73420560 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -1048,14 +1048,11 @@ fn encode_and_write_metadata<'tcx>(
                 tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))
             });
         let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
-        match std::fs::rename(&metadata_filename, &out_filename) {
-            Ok(_) => {
-                if tcx.sess.opts.debugging_opts.emit_directives {
-                    tcx.sess.parse_sess.span_diagnostic.maybe_emit_json_directive(
-                        format!("metadata file written: {}", out_filename.display()));
-                }
-            }
-            Err(e) => tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)),
+        if let Err(e) = fs::rename(&metadata_filename, &out_filename) {
+            tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+        }
+        if tcx.sess.opts.debugging_opts.emit_artifact_notifications {
+            tcx.sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename);
         }
     }
 
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index 65f8d0e77d7be..2dd2ecb749300 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -19,6 +19,7 @@ use errors::emitter::{Emitter, HumanReadableErrorType};
 use syntax_pos::{MacroBacktrace, Span, SpanLabel, MultiSpan};
 use rustc_data_structures::sync::{self, Lrc};
 use std::io::{self, Write};
+use std::path::Path;
 use std::vec;
 use std::sync::{Arc, Mutex};
 
@@ -91,15 +92,15 @@ impl Emitter for JsonEmitter {
         }
     }
 
-    fn maybe_emit_json_directive(&mut self, directive: String) {
-        let data = Directive { directive };
+    fn emit_artifact_notification(&mut self, path: &Path) {
+        let data = ArtifactNotification { artifact: path };
         let result = if self.pretty {
             writeln!(&mut self.dst, "{}", as_pretty_json(&data))
         } else {
             writeln!(&mut self.dst, "{}", as_json(&data))
         };
         if let Err(e) = result {
-            panic!("failed to print message: {:?}", e);
+            panic!("failed to print notification: {:?}", e);
         }
     }
 }
@@ -181,9 +182,9 @@ struct DiagnosticCode {
 }
 
 #[derive(RustcEncodable)]
-struct Directive {
-    /// The directive itself.
-    directive: String,
+struct ArtifactNotification<'a> {
+    /// The path of the artifact.
+    artifact: &'a Path,
 }
 
 impl Diagnostic {
diff --git a/src/test/ui/emit-artifact-notifications.nll.stderr b/src/test/ui/emit-artifact-notifications.nll.stderr
new file mode 100644
index 0000000000000..347d9aeac2307
--- /dev/null
+++ b/src/test/ui/emit-artifact-notifications.nll.stderr
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications.nll/libemit_artifact_notifications.rmeta"}
diff --git a/src/test/ui/emit-artifact-notifications.rs b/src/test/ui/emit-artifact-notifications.rs
new file mode 100644
index 0000000000000..c2c930c8b1bae
--- /dev/null
+++ b/src/test/ui/emit-artifact-notifications.rs
@@ -0,0 +1,6 @@
+// compile-flags:--emit=metadata --error-format=json -Z emit-artifact-notifications
+// compile-pass
+
+// A very basic test for the emission of artifact notifications in JSON output.
+
+fn main() {}
diff --git a/src/test/ui/emit-artifact-notifications.stderr b/src/test/ui/emit-artifact-notifications.stderr
new file mode 100644
index 0000000000000..56c977181ff51
--- /dev/null
+++ b/src/test/ui/emit-artifact-notifications.stderr
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications/libemit_artifact_notifications.rmeta"}
diff --git a/src/test/ui/emit-directives.rs b/src/test/ui/emit-directives.rs
deleted file mode 100644
index 924569d3e232d..0000000000000
--- a/src/test/ui/emit-directives.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// compile-flags:--emit=metadata --error-format=json -Z emit-directives
-// compile-pass
-
-// A very basic test for the emission of build directives in JSON output.
-
-fn main() {}
diff --git a/src/test/ui/emit-directives.stderr b/src/test/ui/emit-directives.stderr
deleted file mode 100644
index 068745edb8dc0..0000000000000
--- a/src/test/ui/emit-directives.stderr
+++ /dev/null
@@ -1 +0,0 @@
-{"directive":"metadata file written: $TEST_BUILD_DIR/emit-directives/libemit_directives.rmeta"}
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 26a3c4dee40aa..d651b9a92b649 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -4,7 +4,7 @@
 use crate::errors::{Error, ErrorKind};
 use crate::runtest::ProcRes;
 use serde_json;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
 #[derive(Deserialize)]
@@ -18,9 +18,9 @@ struct Diagnostic {
 }
 
 #[derive(Deserialize)]
-struct Directive {
+struct ArtifactNotification {
     #[allow(dead_code)]
-    directive: String,
+    artifact: PathBuf,
 }
 
 #[derive(Deserialize, Clone)]
@@ -75,8 +75,8 @@ pub fn extract_rendered(output: &str) -> String {
             if line.starts_with('{') {
                 if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
                     diagnostic.rendered
-                } else if let Ok(_directive) = serde_json::from_str::<Directive>(line) {
-                    // Swallow the directive.
+                } else if let Ok(_) = serde_json::from_str::<ArtifactNotification>(line) {
+                    // Ignore the notification.
                     None
                 } else {
                     print!(

From bb1c67dde4ef2936b4f9b39cf4963584608d3c12 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Thu, 2 May 2019 05:49:57 +0300
Subject: [PATCH 4/5] rustc_codegen_ssa: emit artifact notifications for the
 main link product too.

---
 src/librustc_codegen_ssa/back/link.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index f25891d77ce53..8a751b02b78dd 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -95,6 +95,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
                     );
                 }
             }
+            if sess.opts.debugging_opts.emit_artifact_notifications {
+                sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename);
+            }
         }
 
         if sess.opts.cg.save_temps {

From c89a13179ea1d8431868508d79d57ab3c6ce0ac7 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Tue, 7 May 2019 04:49:26 +0300
Subject: [PATCH 5/5] compiletest: uniformly normalize paths, so they all work
 on all platforms.

---
 src/tools/compiletest/src/runtest.rs | 32 +++++++++++++---------------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 649679e9b3cc0..0e4946736fb7c 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3154,42 +3154,40 @@ impl<'test> TestCx<'test> {
     }
 
     fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String {
-        let parent_dir = self.testpaths.file.parent().unwrap();
         let cflags = self.props.compile_flags.join(" ");
         let json = cflags.contains("--error-format json")
             || cflags.contains("--error-format pretty-json")
             || cflags.contains("--error-format=json")
             || cflags.contains("--error-format=pretty-json");
-        let parent_dir_str = if json {
-            parent_dir.display().to_string().replace("\\", "\\\\")
-        } else {
-            parent_dir.display().to_string()
+
+        let mut normalized = output.to_string();
+
+        let mut normalize_path = |from: &Path, to: &str| {
+            let mut from = from.display().to_string();
+            if json {
+                from = from.replace("\\", "\\\\");
+            }
+            normalized = normalized.replace(&from, to);
         };
 
-        let mut normalized = output.replace(&parent_dir_str, "$DIR");
+        let parent_dir = self.testpaths.file.parent().unwrap();
+        normalize_path(parent_dir, "$DIR");
 
         // Paths into the libstd/libcore
         let src_dir = self.config.src_base.parent().unwrap().parent().unwrap();
-        let src_dir_str = if json {
-            src_dir.display().to_string().replace("\\", "\\\\")
-        } else {
-            src_dir.display().to_string()
-        };
-        normalized = normalized.replace(&src_dir_str, "$SRC_DIR");
+        normalize_path(src_dir, "$SRC_DIR");
 
         // Paths into the build directory
         let test_build_dir = &self.config.build_base;
         let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap();
 
         // eg. /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui
-        normalized = normalized.replace(test_build_dir.to_str().unwrap(), "$TEST_BUILD_DIR");
+        normalize_path(test_build_dir, "$TEST_BUILD_DIR");
         // eg. /home/user/rust/build
-        normalized = normalized.replace(&parent_build_dir.to_str().unwrap(), "$BUILD_DIR");
+        normalize_path(parent_build_dir, "$BUILD_DIR");
 
         // Paths into lib directory.
-        let mut lib_dir = parent_build_dir.parent().unwrap().to_path_buf();
-        lib_dir.push("lib");
-        normalized = normalized.replace(&lib_dir.to_str().unwrap(), "$LIB_DIR");
+        normalize_path(&parent_build_dir.parent().unwrap().join("lib"), "$LIB_DIR");
 
         if json {
             // escaped newlines in json strings should be readable