about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david.wood@huawei.com>2023-07-25 11:12:52 +0100
committerDavid Wood <david.wood@huawei.com>2023-07-25 11:12:52 +0100
commit75df62d4a2c45175b8cb1eb4bdc10fa423c11c4c (patch)
tree67925908692c640333197f19df25fffd2a76bb9f
parentc06a7eb2a6dcbc7649de76472f6845e30f2fb97f (diff)
downloadrust-75df62d4a2c45175b8cb1eb4bdc10fa423c11c4c.tar.gz
rust-75df62d4a2c45175b8cb1eb4bdc10fa423c11c4c.zip
builtin_macros: raw str in diagnostic output
If a raw string was used in the `env!` invocation, then it should also
be shown in the diagnostic messages as a raw string.

Signed-off-by: David Wood <david@davidtw.co>
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl4
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs41
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs52
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs6
-rw-r--r--tests/ui/macros/builtin-env-issue-114010.rs4
-rw-r--r--tests/ui/macros/builtin-env-issue-114010.stderr15
6 files changed, 73 insertions, 49 deletions
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 322222ae330..79fae7f92f1 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -109,8 +109,8 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept
     .suggestion = remove the value
 
 builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
-    .cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead
-    .other = use `std::env::var("{$var}")` to read the variable at run time
+    .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
+    .custom = use `std::env::var({$var_expr})` to read the variable at run time
 
 builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
 
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index 30d74ba593c..92da0c069e5 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -4,7 +4,7 @@
 //
 
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{self as ast, GenericArg};
+use rustc_ast::{self as ast, AstDeref, GenericArg};
 use rustc_expand::base::{self, *};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
@@ -76,27 +76,36 @@ pub fn expand_env<'cx>(
         },
     };
 
-    let sp = cx.with_def_site_ctxt(sp);
+    let span = 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 => {
-            // Use the string literal in the code in the diagnostic to avoid confusing diagnostics,
-            // e.g. when the literal contains escape sequences.
             let ast::ExprKind::Lit(ast::token::Lit {
                 kind: ast::token::LitKind::Str | ast::token::LitKind::StrRaw(..),
-                symbol: original_var,
+                symbol,
                 ..
             }) = &var_expr.kind
             else {
                 unreachable!("`expr_to_string` ensures this is a string lit")
             };
-            cx.emit_err(errors::EnvNotDefined {
-                span: sp,
-                msg: custom_msg,
-                var: *original_var,
-                help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())),
-            });
+
+            if let Some(msg_from_user) = custom_msg {
+                cx.emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user });
+            } else if is_cargo_env_var(var.as_str()) {
+                cx.emit_err(errors::EnvNotDefined::CargoEnvVar {
+                    span,
+                    var: *symbol,
+                    var_expr: var_expr.ast_deref(),
+                });
+            } else {
+                cx.emit_err(errors::EnvNotDefined::CustomEnvVar {
+                    span,
+                    var: *symbol,
+                    var_expr: var_expr.ast_deref(),
+                });
+            }
+
             return DummyResult::any(sp);
         }
         Some(value) => cx.expr_str(sp, value),
@@ -104,13 +113,9 @@ pub fn expand_env<'cx>(
     MacEager::expr(e)
 }
 
-fn help_for_missing_env_var(var: &str) -> errors::EnvNotDefinedHelp {
-    if var.starts_with("CARGO_")
+/// Returns `true` if an environment variable from `env!` is one used by Cargo.
+fn is_cargo_env_var(var: &str) -> bool {
+    var.starts_with("CARGO_")
         || var.starts_with("DEP_")
         || matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET")
-    {
-        errors::EnvNotDefinedHelp::CargoVar
-    } else {
-        errors::EnvNotDefinedHelp::Other
-    }
 }
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 7b2a375a822..fbf0395bb05 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -440,43 +440,43 @@ pub(crate) struct EnvTakesArgs {
     pub(crate) span: Span,
 }
 
-//#[derive(Diagnostic)]
-//#[diag(builtin_macros_env_not_defined)]
-pub(crate) struct EnvNotDefined {
+pub(crate) struct EnvNotDefinedWithUserMessage {
     pub(crate) span: Span,
-    pub(crate) msg: Option<Symbol>,
-    pub(crate) var: Symbol,
-    pub(crate) help: Option<EnvNotDefinedHelp>,
+    pub(crate) msg_from_user: Symbol,
 }
 
-// Hand-written implementation to support custom user messages
-impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined {
+// Hand-written implementation to support custom user messages.
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage {
     #[track_caller]
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
-        let mut diag = if let Some(msg) = self.msg {
-            #[expect(
-                rustc::untranslatable_diagnostic,
-                reason = "cannot translate user-provided messages"
-            )]
-            handler.struct_diagnostic(msg.to_string())
-        } else {
-            handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined)
-        };
-        diag.set_arg("var", self.var);
+        #[expect(
+            rustc::untranslatable_diagnostic,
+            reason = "cannot translate user-provided messages"
+        )]
+        let mut diag = handler.struct_diagnostic(self.msg_from_user.to_string());
         diag.set_span(self.span);
-        if let Some(help) = self.help {
-            diag.subdiagnostic(help);
-        }
         diag
     }
 }
 
-#[derive(Subdiagnostic)]
-pub(crate) enum EnvNotDefinedHelp {
+#[derive(Diagnostic)]
+pub(crate) enum EnvNotDefined<'a> {
+    #[diag(builtin_macros_env_not_defined)]
     #[help(builtin_macros_cargo)]
-    CargoVar,
-    #[help(builtin_macros_other)]
-    Other,
+    CargoEnvVar {
+        #[primary_span]
+        span: Span,
+        var: Symbol,
+        var_expr: &'a rustc_ast::Expr,
+    },
+    #[diag(builtin_macros_env_not_defined)]
+    #[help(builtin_macros_custom)]
+    CustomEnvVar {
+        #[primary_span]
+        span: Span,
+        var: Symbol,
+        var_expr: &'a rustc_ast::Expr,
+    },
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 10fe7fc74a8..fb2e84bb7a1 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -164,6 +164,12 @@ impl IntoDiagnosticArg for hir::ConstContext {
     }
 }
 
+impl IntoDiagnosticArg for ast::Expr {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(pprust::expr_to_string(&self)))
+    }
+}
+
 impl IntoDiagnosticArg for ast::Path {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
diff --git a/tests/ui/macros/builtin-env-issue-114010.rs b/tests/ui/macros/builtin-env-issue-114010.rs
index eb97c767fa2..819b8b1e8ab 100644
--- a/tests/ui/macros/builtin-env-issue-114010.rs
+++ b/tests/ui/macros/builtin-env-issue-114010.rs
@@ -1,6 +1,10 @@
 // unset-rustc-env:oopsie
+// unset-rustc-env:a""a
 
 env![r#"oopsie"#];
 //~^ ERROR environment variable `oopsie` not defined at compile time
 
+env![r#"a""a"#];
+//~^ ERROR environment variable `a""a` not defined at compile time
+
 fn main() {}
diff --git a/tests/ui/macros/builtin-env-issue-114010.stderr b/tests/ui/macros/builtin-env-issue-114010.stderr
index 7934ce1b790..0da42089cce 100644
--- a/tests/ui/macros/builtin-env-issue-114010.stderr
+++ b/tests/ui/macros/builtin-env-issue-114010.stderr
@@ -1,11 +1,20 @@
 error: environment variable `oopsie` not defined at compile time
-  --> $DIR/builtin-env-issue-114010.rs:3:1
+  --> $DIR/builtin-env-issue-114010.rs:4:1
    |
 LL | env![r#"oopsie"#];
    | ^^^^^^^^^^^^^^^^^
    |
-   = help: use `std::env::var("oopsie")` to read the variable at run time
+   = help: use `std::env::var(r#"oopsie"#)` 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: aborting due to previous error
+error: environment variable `a""a` not defined at compile time
+  --> $DIR/builtin-env-issue-114010.rs:7:1
+   |
+LL | env![r#"a""a"#];
+   | ^^^^^^^^^^^^^^^
+   |
+   = help: use `std::env::var(r#"a""a"#)` 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: aborting due to 2 previous errors