use std::env; use std::fs; use std::path::Path; use std::process::{Command, ExitStatus, Stdio}; use std::str; // This code exercises the surface area that we expect of the Error generic // member access API. If the current toolchain is able to compile it, then // thiserror is able to provide backtrace support. const PROBE: &str = r#" #![feature(error_generic_member_access)] use std::error::{Error, Request}; use std::fmt::{self, Debug, Display}; struct MyError(Thing); struct Thing; impl Debug for MyError { fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } } impl Display for MyError { fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } } impl Error for MyError { fn provide<'a>(&'a self, request: &mut Request<'a>) { request.provide_ref(&self.0); } } "#; fn main() { match compile_probe() { Some(status) if status.success() => println!("cargo:rustc-cfg=error_generic_member_access"), _ => {} } } fn compile_probe() -> Option { if env::var_os("RUSTC_STAGE").is_some() { // We are running inside rustc bootstrap. This is a highly non-standard // environment with issues such as: // // https://github.com/rust-lang/cargo/issues/11138 // https://github.com/rust-lang/rust/issues/114839 // // Let's just not use nightly features here. return None; } let rustc = env::var_os("RUSTC")?; let out_dir = env::var_os("OUT_DIR")?; let probefile = Path::new(&out_dir).join("probe.rs"); fs::write(&probefile, PROBE).ok()?; // Make sure to pick up Cargo rustc configuration. let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") { let mut cmd = Command::new(wrapper); // The wrapper's first argument is supposed to be the path to rustc. cmd.arg(rustc); cmd } else { Command::new(rustc) }; cmd.stderr(Stdio::null()) .arg("--edition=2018") .arg("--crate-name=thiserror_build") .arg("--crate-type=lib") .arg("--emit=metadata") .arg("--out-dir") .arg(out_dir) .arg(probefile); if let Some(target) = env::var_os("TARGET") { cmd.arg("--target").arg(target); } // If Cargo wants to set RUSTFLAGS, use that. if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { if !rustflags.is_empty() { for arg in rustflags.split('\x1f') { cmd.arg(arg); } } } cmd.status().ok() }