Skip to content

Commit 2407b0c

Browse files
committed
Explain compile-time vs run-time difference in env!() error message
1 parent 31f858d commit 2407b0c

File tree

5 files changed

+43
-20
lines changed

5 files changed

+43
-20
lines changed

compiler/rustc_builtin_macros/src/env.rs

+30-10
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn expand_env<'cx>(
5353
tts: TokenStream,
5454
) -> Box<dyn base::MacResult + 'cx> {
5555
let mut exprs = match get_exprs_from_tts(cx, tts) {
56-
Some(exprs) if exprs.is_empty() => {
56+
Some(exprs) if exprs.is_empty() || exprs.len() > 2 => {
5757
cx.span_err(sp, "env! takes 1 or 2 arguments");
5858
return DummyResult::any(sp);
5959
}
@@ -64,28 +64,48 @@ pub fn expand_env<'cx>(
6464
let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else {
6565
return DummyResult::any(sp);
6666
};
67-
let msg = match exprs.next() {
68-
None => Symbol::intern(&format!("environment variable `{}` not defined", var)),
67+
68+
let custom_msg = match exprs.next() {
69+
None => None,
6970
Some(second) => match expr_to_string(cx, second, "expected string literal") {
7071
None => return DummyResult::any(sp),
71-
Some((s, _style)) => s,
72+
Some((s, _style)) => Some(s),
7273
},
7374
};
7475

75-
if exprs.next().is_some() {
76-
cx.span_err(sp, "env! takes 1 or 2 arguments");
77-
return DummyResult::any(sp);
78-
}
79-
8076
let sp = cx.with_def_site_ctxt(sp);
8177
let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern);
8278
cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
8379
let e = match value {
8480
None => {
85-
cx.span_err(sp, msg.as_str());
81+
let (msg, help) = match custom_msg {
82+
None => (
83+
format!("environment variable `{var}` not defined at compile time"),
84+
Some(help_for_missing_env_var(var.as_str())),
85+
),
86+
Some(s) => (s.to_string(), None),
87+
};
88+
let mut diag = cx.struct_span_err(sp, &msg);
89+
if let Some(help) = help {
90+
diag.help(help);
91+
}
92+
diag.emit();
8693
return DummyResult::any(sp);
8794
}
8895
Some(value) => cx.expr_str(sp, value),
8996
};
9097
MacEager::expr(e)
9198
}
99+
100+
fn help_for_missing_env_var(var: &str) -> String {
101+
if var.starts_with("CARGO_")
102+
|| var.starts_with("DEP_")
103+
|| matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
104+
{
105+
format!(
106+
"Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead"
107+
)
108+
} else {
109+
format!("Use `std::env::var(\"{var}\")` to read the variable at run time")
110+
}
111+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
fn main() {
2-
env!("__HOPEFULLY_NOT_DEFINED__");
3-
//~^ ERROR: environment variable `__HOPEFULLY_NOT_DEFINED__` not defined
2+
env!("CARGO__HOPEFULLY_NOT_DEFINED__");
3+
//~^ ERROR: environment variable `CARGO__HOPEFULLY_NOT_DEFINED__` not defined
44
}

tests/ui/extenv/extenv-not-defined-default.stderr

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
error: environment variable `__HOPEFULLY_NOT_DEFINED__` not defined
1+
error: environment variable `CARGO__HOPEFULLY_NOT_DEFINED__` not defined at compile time
22
--> $DIR/extenv-not-defined-default.rs:2:5
33
|
4-
LL | env!("__HOPEFULLY_NOT_DEFINED__");
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | env!("CARGO__HOPEFULLY_NOT_DEFINED__");
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7+
= help: Cargo sets build script variables at run time. Use `std::env::var("CARGO__HOPEFULLY_NOT_DEFINED__")` instead
78
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
89

910
error: aborting due to previous error

tests/ui/extenv/issue-55897.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
error: environment variable `NON_EXISTENT` not defined
1+
error: environment variable `NON_EXISTENT` not defined at compile time
22
--> $DIR/issue-55897.rs:11:22
33
|
44
LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs"));
55
| ^^^^^^^^^^^^^^^^^^^^
66
|
7+
= help: Use `std::env::var("NON_EXISTENT")` to read the variable at run time
78
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
89

910
error: suffixes on string literals are invalid

tests/ui/macros/macros-nonfatal-errors.stderr

+5-4
Original file line numberDiff line numberDiff line change
@@ -150,18 +150,19 @@ error: expected string literal
150150
LL | env!(invalid);
151151
| ^^^^^^^
152152

153-
error: expected string literal
154-
--> $DIR/macros-nonfatal-errors.rs:105:10
153+
error: env! takes 1 or 2 arguments
154+
--> $DIR/macros-nonfatal-errors.rs:105:5
155155
|
156156
LL | env!(foo, abr, baz);
157-
| ^^^
157+
| ^^^^^^^^^^^^^^^^^^^
158158

159-
error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
159+
error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at compile time
160160
--> $DIR/macros-nonfatal-errors.rs:106:5
161161
|
162162
LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
163163
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
164164
|
165+
= help: Use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time
165166
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
166167

167168
error: format argument must be a string literal

0 commit comments

Comments
 (0)