about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/proc-macro-api/src/lib.rs10
-rw-r--r--crates/proc-macro-api/src/process.rs51
-rw-r--r--crates/proc-macro-srv-cli/src/main.rs3
3 files changed, 52 insertions, 12 deletions
diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs
index a87becd63e2..208051113a7 100644
--- a/crates/proc-macro-api/src/lib.rs
+++ b/crates/proc-macro-api/src/lib.rs
@@ -14,8 +14,10 @@ mod version;
 use indexmap::IndexSet;
 use paths::AbsPathBuf;
 use span::Span;
-use std::{fmt, io, sync::Mutex};
-use triomphe::Arc;
+use std::{
+    fmt, io,
+    sync::{Arc, Mutex},
+};
 
 use serde::{Deserialize, Serialize};
 
@@ -81,9 +83,11 @@ impl PartialEq for ProcMacro {
     }
 }
 
+#[derive(Clone, Debug)]
 pub struct ServerError {
     pub message: String,
-    pub io: Option<io::Error>,
+    // io::Error isn't Clone for some reason
+    pub io: Option<Arc<io::Error>>,
 }
 
 impl fmt::Display for ServerError {
diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs
index 3494164c067..a22d8628f16 100644
--- a/crates/proc-macro-api/src/process.rs
+++ b/crates/proc-macro-api/src/process.rs
@@ -1,8 +1,9 @@
 //! Handle process life-time and message passing for proc-macro client
 
 use std::{
-    io::{self, BufRead, BufReader, Write},
+    io::{self, BufRead, BufReader, Read, Write},
     process::{Child, ChildStdin, ChildStdout, Command, Stdio},
+    sync::Arc,
 };
 
 use paths::{AbsPath, AbsPathBuf};
@@ -15,9 +16,11 @@ use crate::{
 
 #[derive(Debug)]
 pub(crate) struct ProcMacroProcessSrv {
-    _process: Process,
+    process: Process,
     stdin: ChildStdin,
     stdout: BufReader<ChildStdout>,
+    /// Populated when the server exits.
+    server_exited: Option<ServerError>,
     version: u32,
     mode: SpanMode,
 }
@@ -29,9 +32,10 @@ impl ProcMacroProcessSrv {
             let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
 
             io::Result::Ok(ProcMacroProcessSrv {
-                _process: process,
+                process,
                 stdin,
                 stdout,
+                server_exited: None,
                 version: 0,
                 mode: SpanMode::Id,
             })
@@ -105,8 +109,35 @@ impl ProcMacroProcessSrv {
     }
 
     pub(crate) fn send_task(&mut self, req: Request) -> Result<Response, ServerError> {
+        if let Some(server_error) = &self.server_exited {
+            return Err(server_error.clone());
+        }
+
         let mut buf = String::new();
-        send_request(&mut self.stdin, &mut self.stdout, req, &mut buf)
+        send_request(&mut self.stdin, &mut self.stdout, req, &mut buf).map_err(|e| {
+            if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) {
+                match self.process.child.try_wait() {
+                    Ok(None) => e,
+                    Ok(Some(status)) => {
+                        let mut msg = String::new();
+                        if !status.success() {
+                            if let Some(stderr) = self.process.child.stderr.as_mut() {
+                                _ = stderr.read_to_string(&mut msg);
+                            }
+                        }
+                        let server_error = ServerError {
+                            message: format!("server exited with {status}: {msg}"),
+                            io: None,
+                        };
+                        self.server_exited = Some(server_error.clone());
+                        server_error
+                    }
+                    Err(_) => e,
+                }
+            } else {
+                e
+            }
+        })
     }
 }
 
@@ -145,9 +176,13 @@ fn send_request(
     req: Request,
     buf: &mut String,
 ) -> Result<Response, ServerError> {
-    req.write(&mut writer)
-        .map_err(|err| ServerError { message: "failed to write request".into(), io: Some(err) })?;
-    let res = Response::read(&mut reader, buf)
-        .map_err(|err| ServerError { message: "failed to read response".into(), io: Some(err) })?;
+    req.write(&mut writer).map_err(|err| ServerError {
+        message: "failed to write request".into(),
+        io: Some(Arc::new(err)),
+    })?;
+    let res = Response::read(&mut reader, buf).map_err(|err| ServerError {
+        message: "failed to read response".into(),
+        io: Some(Arc::new(err)),
+    })?;
     res.ok_or_else(|| ServerError { message: "server exited".into(), io: None })
 }
diff --git a/crates/proc-macro-srv-cli/src/main.rs b/crates/proc-macro-srv-cli/src/main.rs
index 87f7555b02c..af9a03826ff 100644
--- a/crates/proc-macro-srv-cli/src/main.rs
+++ b/crates/proc-macro-srv-cli/src/main.rs
@@ -24,7 +24,8 @@ fn main() -> std::io::Result<()> {
 
 #[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))]
 fn run() -> io::Result<()> {
-    panic!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled");
+    eprintln!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled");
+    std::process::exit(70);
 }
 
 #[cfg(any(feature = "sysroot-abi", rust_analyzer))]