]>
Commit | Line | Data |
---|---|---|
c295e0f8 XL |
1 | #![allow(clippy::option_if_let_else)] |
2 | ||
dfeec247 XL |
3 | use std::env; |
4 | use std::fs; | |
5 | use std::path::Path; | |
f035d41b | 6 | use std::process::{Command, ExitStatus, Stdio}; |
5869c6ff | 7 | use std::str; |
dfeec247 | 8 | |
cdc7bbd5 XL |
9 | #[cfg(all(feature = "backtrace", not(feature = "std")))] |
10 | compile_error! { | |
11 | "`backtrace` feature without `std` feature is not supported" | |
12 | } | |
13 | ||
add651ee FG |
14 | // This code exercises the surface area that we expect of the Error generic |
15 | // member access API. If the current toolchain is able to compile it, then | |
16 | // anyhow is able to provide backtrace support. | |
dfeec247 | 17 | const PROBE: &str = r#" |
add651ee | 18 | #![feature(error_generic_member_access)] |
dfeec247 | 19 | |
add651ee FG |
20 | use std::backtrace::Backtrace; |
21 | use std::error::{self, Error, Request}; | |
22 | use std::fmt::{self, Debug, Display}; | |
dfeec247 | 23 | |
add651ee FG |
24 | struct MyError(Thing); |
25 | struct Thing; | |
dfeec247 | 26 | |
add651ee | 27 | impl Debug for MyError { |
dfeec247 XL |
28 | fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { |
29 | unimplemented!() | |
30 | } | |
31 | } | |
32 | ||
add651ee FG |
33 | impl Display for MyError { |
34 | fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { | |
35 | unimplemented!() | |
dfeec247 XL |
36 | } |
37 | } | |
f2b60f7d | 38 | |
add651ee FG |
39 | impl Error for MyError { |
40 | fn provide<'a>(&'a self, request: &mut Request<'a>) { | |
41 | request.provide_ref(&self.0); | |
f2b60f7d | 42 | } |
add651ee | 43 | } |
f2b60f7d | 44 | |
add651ee | 45 | const _: fn(&dyn Error) -> Option<&Backtrace> = |err| error::request_ref::<Backtrace>(err); |
dfeec247 XL |
46 | "#; |
47 | ||
48 | fn main() { | |
5869c6ff XL |
49 | if cfg!(feature = "std") { |
50 | match compile_probe() { | |
51 | Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"), | |
52 | _ => {} | |
53 | } | |
dfeec247 | 54 | } |
5869c6ff XL |
55 | |
56 | let rustc = match rustc_minor_version() { | |
57 | Some(rustc) => rustc, | |
58 | None => return, | |
59 | }; | |
60 | ||
cdc7bbd5 XL |
61 | if rustc < 51 { |
62 | println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of"); | |
63 | } | |
a2a8927a XL |
64 | |
65 | if rustc < 52 { | |
66 | println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str"); | |
67 | } | |
dfeec247 XL |
68 | } |
69 | ||
70 | fn compile_probe() -> Option<ExitStatus> { | |
add651ee FG |
71 | if env::var_os("RUSTC_STAGE").is_some() { |
72 | // We are running inside rustc bootstrap. This is a highly non-standard | |
73 | // environment with issues such as: | |
74 | // | |
75 | // https://github.com/rust-lang/cargo/issues/11138 | |
76 | // https://github.com/rust-lang/rust/issues/114839 | |
77 | // | |
78 | // Let's just not use nightly features here. | |
79 | return None; | |
80 | } | |
81 | ||
dfeec247 XL |
82 | let rustc = env::var_os("RUSTC")?; |
83 | let out_dir = env::var_os("OUT_DIR")?; | |
84 | let probefile = Path::new(&out_dir).join("probe.rs"); | |
85 | fs::write(&probefile, PROBE).ok()?; | |
c295e0f8 XL |
86 | |
87 | // Make sure to pick up Cargo rustc configuration. | |
064997fb | 88 | let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") { |
c295e0f8 XL |
89 | let mut cmd = Command::new(wrapper); |
90 | // The wrapper's first argument is supposed to be the path to rustc. | |
91 | cmd.arg(rustc); | |
92 | cmd | |
93 | } else { | |
94 | Command::new(rustc) | |
95 | }; | |
96 | ||
97 | cmd.stderr(Stdio::null()) | |
dfeec247 XL |
98 | .arg("--edition=2018") |
99 | .arg("--crate-name=anyhow_build") | |
100 | .arg("--crate-type=lib") | |
101 | .arg("--emit=metadata") | |
102 | .arg("--out-dir") | |
103 | .arg(out_dir) | |
c295e0f8 XL |
104 | .arg(probefile); |
105 | ||
064997fb FG |
106 | if let Some(target) = env::var_os("TARGET") { |
107 | cmd.arg("--target").arg(target); | |
108 | } | |
109 | ||
c295e0f8 XL |
110 | // If Cargo wants to set RUSTFLAGS, use that. |
111 | if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { | |
112 | if !rustflags.is_empty() { | |
113 | for arg in rustflags.split('\x1f') { | |
114 | cmd.arg(arg); | |
115 | } | |
116 | } | |
117 | } | |
118 | ||
119 | cmd.status().ok() | |
dfeec247 | 120 | } |
5869c6ff XL |
121 | |
122 | fn rustc_minor_version() -> Option<u32> { | |
123 | let rustc = env::var_os("RUSTC")?; | |
124 | let output = Command::new(rustc).arg("--version").output().ok()?; | |
125 | let version = str::from_utf8(&output.stdout).ok()?; | |
126 | let mut pieces = version.split('.'); | |
127 | if pieces.next() != Some("rustc 1") { | |
128 | return None; | |
129 | } | |
130 | pieces.next()?.parse().ok() | |
131 | } |