about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKornel <kornel@geekhood.net>2023-02-28 16:20:43 +0000
committerKornel <kornel@geekhood.net>2023-02-28 16:44:59 +0000
commit2407b0c5787e731f9ed39ad180d87de166fa54bf (patch)
treebf306078edd514d40b377eafab5adeb924411315
parent31f858d9a511f24fedb8ed997b28304fec809630 (diff)
downloadrust-2407b0c5787e731f9ed39ad180d87de166fa54bf.tar.gz
rust-2407b0c5787e731f9ed39ad180d87de166fa54bf.zip
Explain compile-time vs run-time difference in env!() error message
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs40
-rw-r--r--tests/ui/extenv/extenv-not-defined-default.rs4
-rw-r--r--tests/ui/extenv/extenv-not-defined-default.stderr7
-rw-r--r--tests/ui/extenv/issue-55897.stderr3
-rw-r--r--tests/ui/macros/macros-nonfatal-errors.stderr9
5 files changed, 43 insertions, 20 deletions
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index 6aa900f0201..f011cb754cb 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -53,7 +53,7 @@ pub fn expand_env<'cx>(
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'cx> {
     let mut exprs = match get_exprs_from_tts(cx, tts) {
-        Some(exprs) if exprs.is_empty() => {
+        Some(exprs) if exprs.is_empty() || exprs.len() > 2 => {
             cx.span_err(sp, "env! takes 1 or 2 arguments");
             return DummyResult::any(sp);
         }
@@ -64,28 +64,48 @@ pub fn expand_env<'cx>(
     let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else {
         return DummyResult::any(sp);
     };
-    let msg = match exprs.next() {
-        None => Symbol::intern(&format!("environment variable `{}` not defined", var)),
+
+    let custom_msg = match exprs.next() {
+        None => None,
         Some(second) => match expr_to_string(cx, second, "expected string literal") {
             None => return DummyResult::any(sp),
-            Some((s, _style)) => s,
+            Some((s, _style)) => Some(s),
         },
     };
 
-    if exprs.next().is_some() {
-        cx.span_err(sp, "env! takes 1 or 2 arguments");
-        return DummyResult::any(sp);
-    }
-
     let sp = cx.with_def_site_ctxt(sp);
     let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern);
     cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
     let e = match value {
         None => {
-            cx.span_err(sp, msg.as_str());
+            let (msg, help) = match custom_msg {
+                None => (
+                    format!("environment variable `{var}` not defined at compile time"),
+                    Some(help_for_missing_env_var(var.as_str())),
+                ),
+                Some(s) => (s.to_string(), None),
+            };
+            let mut diag = cx.struct_span_err(sp, &msg);
+            if let Some(help) = help {
+                diag.help(help);
+            }
+            diag.emit();
             return DummyResult::any(sp);
         }
         Some(value) => cx.expr_str(sp, value),
     };
     MacEager::expr(e)
 }
+
+fn help_for_missing_env_var(var: &str) -> String {
+    if var.starts_with("CARGO_")
+        || var.starts_with("DEP_")
+        || matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
+    {
+        format!(
+            "Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead"
+        )
+    } else {
+        format!("Use `std::env::var(\"{var}\")` to read the variable at run time")
+    }
+}
diff --git a/tests/ui/extenv/extenv-not-defined-default.rs b/tests/ui/extenv/extenv-not-defined-default.rs
index 30a06a25465..1fb046c78f2 100644
--- a/tests/ui/extenv/extenv-not-defined-default.rs
+++ b/tests/ui/extenv/extenv-not-defined-default.rs
@@ -1,4 +1,4 @@
 fn main() {
-    env!("__HOPEFULLY_NOT_DEFINED__");
-    //~^ ERROR: environment variable `__HOPEFULLY_NOT_DEFINED__` not defined
+    env!("CARGO__HOPEFULLY_NOT_DEFINED__");
+    //~^ ERROR: environment variable `CARGO__HOPEFULLY_NOT_DEFINED__` not defined
 }
diff --git a/tests/ui/extenv/extenv-not-defined-default.stderr b/tests/ui/extenv/extenv-not-defined-default.stderr
index 884875dca53..e3dce000530 100644
--- a/tests/ui/extenv/extenv-not-defined-default.stderr
+++ b/tests/ui/extenv/extenv-not-defined-default.stderr
@@ -1,9 +1,10 @@
-error: environment variable `__HOPEFULLY_NOT_DEFINED__` not defined
+error: environment variable `CARGO__HOPEFULLY_NOT_DEFINED__` not defined at compile time
   --> $DIR/extenv-not-defined-default.rs:2:5
    |
-LL |     env!("__HOPEFULLY_NOT_DEFINED__");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     env!("CARGO__HOPEFULLY_NOT_DEFINED__");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = help: Cargo sets build script variables at run time. Use `std::env::var("CARGO__HOPEFULLY_NOT_DEFINED__")` instead
    = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
diff --git a/tests/ui/extenv/issue-55897.stderr b/tests/ui/extenv/issue-55897.stderr
index 92e8a44b55f..5752a965e35 100644
--- a/tests/ui/extenv/issue-55897.stderr
+++ b/tests/ui/extenv/issue-55897.stderr
@@ -1,9 +1,10 @@
-error: environment variable `NON_EXISTENT` not defined
+error: environment variable `NON_EXISTENT` not defined at compile time
   --> $DIR/issue-55897.rs:11:22
    |
 LL |     include!(concat!(env!("NON_EXISTENT"), "/data.rs"));
    |                      ^^^^^^^^^^^^^^^^^^^^
    |
+   = help: Use `std::env::var("NON_EXISTENT")` to read the variable at run time
    = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: suffixes on string literals are invalid
diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr
index d42f6c179b7..93fbc9c8a44 100644
--- a/tests/ui/macros/macros-nonfatal-errors.stderr
+++ b/tests/ui/macros/macros-nonfatal-errors.stderr
@@ -150,18 +150,19 @@ error: expected string literal
 LL |     env!(invalid);
    |          ^^^^^^^
 
-error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:105:10
+error: env! takes 1 or 2 arguments
+  --> $DIR/macros-nonfatal-errors.rs:105:5
    |
 LL |     env!(foo, abr, baz);
-   |          ^^^
+   |     ^^^^^^^^^^^^^^^^^^^
 
-error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
+error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at compile time
   --> $DIR/macros-nonfatal-errors.rs:106:5
    |
 LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = help: Use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time
    = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: format argument must be a string literal